push 4764fdcba48f6a6df3263056e605233f2bb574ff
[wine/hacks.git] / dlls / wined3d / device.c
blobc1a8364601cbb1855a604aae68c2ffd5b5277758
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
145 /**********************************************************
146 * Global variable / Constants follow
147 **********************************************************/
148 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
150 /**********************************************************
151 * IUnknown parts follows
152 **********************************************************/
154 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
158 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
159 if (IsEqualGUID(riid, &IID_IUnknown)
160 || IsEqualGUID(riid, &IID_IWineD3DBase)
161 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
162 IUnknown_AddRef(iface);
163 *ppobj = This;
164 return S_OK;
166 *ppobj = NULL;
167 return E_NOINTERFACE;
170 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
175 return refCount;
178 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
180 ULONG refCount = InterlockedDecrement(&This->ref);
182 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 if (!refCount) {
185 if (This->fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
188 if (This->src_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
191 if (This->dst_fbo) {
192 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
195 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
197 /* TODO: Clean up all the surfaces and textures! */
198 /* NOTE: You must release the parent if the object was created via a callback
199 ** ***************************/
201 if (This->resources != NULL ) {
202 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
203 dumpResources(This->resources);
206 if(This->contexts) ERR("Context array not freed!\n");
207 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
208 This->haveHardwareCursor = FALSE;
210 IWineD3D_Release(This->wineD3D);
211 This->wineD3D = NULL;
212 HeapFree(GetProcessHeap(), 0, This);
213 TRACE("Freed device %p\n", This);
214 This = NULL;
216 return refCount;
219 /**********************************************************
220 * IWineD3DDevice implementation follows
221 **********************************************************/
222 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
224 *pParent = This->parent;
225 IUnknown_AddRef(This->parent);
226 return WINED3D_OK;
229 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
230 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
231 GLenum error, glUsage;
232 DWORD vboUsage = object->resource.usage;
233 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
234 WARN("Creating a vbo failed once, not trying again\n");
235 return;
238 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
240 ENTER_GL();
241 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
242 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
244 /* Make sure that the gl error is cleared. Do not use checkGLcall
245 * here because checkGLcall just prints a fixme and continues. However,
246 * if an error during VBO creation occurs we can fall back to non-vbo operation
247 * with full functionality(but performance loss)
249 while(glGetError() != GL_NO_ERROR);
251 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
252 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
253 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
254 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
255 * to check if the rhw and color values are in the correct format.
258 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
259 error = glGetError();
260 if(object->vbo == 0 || error != GL_NO_ERROR) {
261 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
262 goto error;
265 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
266 error = glGetError();
267 if(error != GL_NO_ERROR) {
268 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
269 goto error;
272 /* Don't use static, because dx apps tend to update the buffer
273 * quite often even if they specify 0 usage. Because we always keep the local copy
274 * we never read from the vbo and can create a write only opengl buffer.
276 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
277 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
278 case WINED3DUSAGE_DYNAMIC:
279 TRACE("Gl usage = GL_STREAM_DRAW\n");
280 glUsage = GL_STREAM_DRAW_ARB;
281 break;
282 case WINED3DUSAGE_WRITEONLY:
283 default:
284 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
285 glUsage = GL_DYNAMIC_DRAW_ARB;
286 break;
289 /* Reserve memory for the buffer. The amount of data won't change
290 * so we are safe with calling glBufferData once with a NULL ptr and
291 * calling glBufferSubData on updates
293 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
294 error = glGetError();
295 if(error != GL_NO_ERROR) {
296 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
297 goto error;
300 LEAVE_GL();
302 return;
303 error:
304 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
305 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
306 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
307 object->vbo = 0;
308 object->Flags |= VBFLAG_VBOCREATEFAIL;
309 LEAVE_GL();
310 return;
313 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
314 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
315 IUnknown *parent) {
316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
317 IWineD3DVertexBufferImpl *object;
318 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
319 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
320 BOOL conv;
322 if(Size == 0) {
323 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
324 *ppVertexBuffer = NULL;
325 return WINED3DERR_INVALIDCALL;
328 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
330 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
331 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
333 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
334 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
336 object->fvf = FVF;
338 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
339 * drawStridedFast (half-life 2).
341 * Basically converting the vertices in the buffer is quite expensive, and observations
342 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
343 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
345 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
346 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
347 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
348 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
349 * dx7 apps.
350 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
351 * more. In this call we can convert dx7 buffers too.
353 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
354 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
355 (dxVersion > 7 || !conv) ) {
356 CreateVBO(object);
358 return WINED3D_OK;
361 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
362 GLenum error, glUsage;
363 TRACE("Creating VBO for Index Buffer %p\n", object);
365 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
366 * restored on the next draw
368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
370 ENTER_GL();
371 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
372 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
374 while(glGetError());
376 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
377 error = glGetError();
378 if(error != GL_NO_ERROR || object->vbo == 0) {
379 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
380 goto out;
383 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
384 error = glGetError();
385 if(error != GL_NO_ERROR) {
386 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
387 goto out;
390 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
391 * copy no readback will be needed
393 glUsage = GL_STATIC_DRAW_ARB;
394 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
395 error = glGetError();
396 if(error != GL_NO_ERROR) {
397 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
398 goto out;
400 LEAVE_GL();
401 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
402 return;
404 out:
405 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
406 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
407 LEAVE_GL();
408 object->vbo = 0;
411 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
412 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
413 HANDLE *sharedHandle, IUnknown *parent) {
414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
415 IWineD3DIndexBufferImpl *object;
416 TRACE("(%p) Creating index buffer\n", This);
418 /* Allocate the storage for the device */
419 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
421 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
422 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
433 return WINED3D_OK;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
440 int i, j;
441 HRESULT temp_result;
443 D3DCREATEOBJECTINSTANCE(object, StateBlock)
444 object->blockType = Type;
446 for(i = 0; i < LIGHTMAP_SIZE; i++) {
447 list_init(&object->lightMap[i]);
450 /* Special case - Used during initialization to produce a placeholder stateblock
451 so other functions called can update a state block */
452 if (Type == WINED3DSBT_INIT) {
453 /* Don't bother increasing the reference count otherwise a device will never
454 be freed due to circular dependencies */
455 return WINED3D_OK;
458 temp_result = allocate_shader_constants(object);
459 if (WINED3D_OK != temp_result)
460 return temp_result;
462 /* Otherwise, might as well set the whole state block to the appropriate values */
463 if (This->stateBlock != NULL)
464 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
465 else
466 memset(object->streamFreq, 1, sizeof(object->streamFreq));
468 /* Reset the ref and type after kludging it */
469 object->wineD3DDevice = This;
470 object->ref = 1;
471 object->blockType = Type;
473 TRACE("Updating changed flags appropriate for type %d\n", Type);
475 if (Type == WINED3DSBT_ALL) {
477 TRACE("ALL => Pretend everything has changed\n");
478 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
480 /* Lights are not part of the changed / set structure */
481 for(j = 0; j < LIGHTMAP_SIZE; j++) {
482 struct list *e;
483 LIST_FOR_EACH(e, &object->lightMap[j]) {
484 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
485 light->changed = TRUE;
486 light->enabledChanged = TRUE;
489 } else if (Type == WINED3DSBT_PIXELSTATE) {
491 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
492 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
494 object->changed.pixelShader = TRUE;
496 /* Pixel Shader Constants */
497 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
498 object->changed.pixelShaderConstantsF[i] = TRUE;
499 for (i = 0; i < MAX_CONST_B; ++i)
500 object->changed.pixelShaderConstantsB[i] = TRUE;
501 for (i = 0; i < MAX_CONST_I; ++i)
502 object->changed.pixelShaderConstantsI[i] = TRUE;
504 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
505 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
507 for (j = 0; j < MAX_TEXTURES; j++) {
508 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
509 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
512 for (j = 0 ; j < 16; j++) {
513 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
515 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
519 } else if (Type == WINED3DSBT_VERTEXSTATE) {
521 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
522 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
524 object->changed.vertexShader = TRUE;
526 /* Vertex Shader Constants */
527 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
528 object->changed.vertexShaderConstantsF[i] = TRUE;
529 for (i = 0; i < MAX_CONST_B; ++i)
530 object->changed.vertexShaderConstantsB[i] = TRUE;
531 for (i = 0; i < MAX_CONST_I; ++i)
532 object->changed.vertexShaderConstantsI[i] = TRUE;
534 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
535 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 for (j = 0; j < MAX_TEXTURES; j++) {
538 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
539 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
542 for (j = 0 ; j < 16; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
548 for(j = 0; j < LIGHTMAP_SIZE; j++) {
549 struct list *e;
550 LIST_FOR_EACH(e, &object->lightMap[j]) {
551 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
552 light->changed = TRUE;
553 light->enabledChanged = TRUE;
556 } else {
557 FIXME("Unrecognized state block type %d\n", Type);
560 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
561 return WINED3D_OK;
564 /* ************************************
565 MSDN:
566 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
568 Discard
569 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
571 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
573 ******************************** */
575 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
577 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
578 unsigned int Size = 1;
579 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
580 TRACE("(%p) Create surface\n",This);
582 /** FIXME: Check ranges on the inputs are valid
583 * MSDN
584 * MultisampleQuality
585 * [in] Quality level. The valid range is between zero and one less than the level
586 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
587 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
588 * values of paired render targets, depth stencil surfaces, and the MultiSample type
589 * must all match.
590 *******************************/
594 * TODO: Discard MSDN
595 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
597 * If this flag is set, the contents of the depth stencil buffer will be
598 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
599 * with a different depth surface.
601 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
602 ***************************/
604 if(MultisampleQuality < 0) {
605 FIXME("Invalid multisample level %d\n", MultisampleQuality);
606 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
609 if(MultisampleQuality > 0) {
610 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
611 MultisampleQuality=0;
614 /** FIXME: Check that the format is supported
615 * by the device.
616 *******************************/
618 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
619 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
620 * space!
621 *********************************/
622 if (WINED3DFMT_UNKNOWN == Format) {
623 Size = 0;
624 } else if (Format == WINED3DFMT_DXT1) {
625 /* DXT1 is half byte per pixel */
626 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
628 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
629 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
630 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
631 } else {
632 /* The pitch is a multiple of 4 bytes */
633 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
634 Size *= Height;
637 /** Create and initialise the surface resource **/
638 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
639 /* "Standalone" surface */
640 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
642 object->currentDesc.Width = Width;
643 object->currentDesc.Height = Height;
644 object->currentDesc.MultiSampleType = MultiSample;
645 object->currentDesc.MultiSampleQuality = MultisampleQuality;
646 object->glDescription.level = Level;
648 /* Flags */
649 object->Flags = 0;
650 object->Flags |= Discard ? SFLAG_DISCARD : 0;
651 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
652 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
655 if (WINED3DFMT_UNKNOWN != Format) {
656 object->bytesPerPixel = tableEntry->bpp;
657 } else {
658 object->bytesPerPixel = 0;
661 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
663 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
665 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
666 * this function is too deep to need to care about things like this.
667 * Levels need to be checked too, and possibly Type since they all affect what can be done.
668 * ****************************************/
669 switch(Pool) {
670 case WINED3DPOOL_SCRATCH:
671 if(!Lockable)
672 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
673 "which are mutually exclusive, setting lockable to TRUE\n");
674 Lockable = TRUE;
675 break;
676 case WINED3DPOOL_SYSTEMMEM:
677 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
678 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
679 case WINED3DPOOL_MANAGED:
680 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
681 "Usage of DYNAMIC which are mutually exclusive, not doing "
682 "anything just telling you.\n");
683 break;
684 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
685 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
686 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
687 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
688 break;
689 default:
690 FIXME("(%p) Unknown pool %d\n", This, Pool);
691 break;
694 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
695 FIXME("Trying to create a render target that isn't in the default pool\n");
698 /* mark the texture as dirty so that it gets loaded first time around*/
699 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
700 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
701 This, Width, Height, Format, debug_d3dformat(Format),
702 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
704 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
705 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
706 This->ddraw_primary = (IWineD3DSurface *) object;
708 /* Look at the implementation and set the correct Vtable */
709 switch(Impl) {
710 case SURFACE_OPENGL:
711 /* Check if a 3D adapter is available when creating gl surfaces */
712 if(!This->adapter) {
713 ERR("OpenGL surfaces are not available without opengl\n");
714 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
715 HeapFree(GetProcessHeap(), 0, object);
716 return WINED3DERR_NOTAVAILABLE;
718 break;
720 case SURFACE_GDI:
721 object->lpVtbl = &IWineGDISurface_Vtbl;
722 break;
724 default:
725 /* To be sure to catch this */
726 ERR("Unknown requested surface implementation %d!\n", Impl);
727 IWineD3DSurface_Release((IWineD3DSurface *) object);
728 return WINED3DERR_INVALIDCALL;
731 list_init(&object->renderbuffers);
733 /* Call the private setup routine */
734 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
738 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
739 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
740 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
741 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
744 IWineD3DTextureImpl *object;
745 unsigned int i;
746 UINT tmpW;
747 UINT tmpH;
748 HRESULT hr;
749 unsigned int pow2Width;
750 unsigned int pow2Height;
753 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
754 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
755 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
757 /* TODO: It should only be possible to create textures for formats
758 that are reported as supported */
759 if (WINED3DFMT_UNKNOWN >= Format) {
760 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
761 return WINED3DERR_INVALIDCALL;
764 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
765 D3DINITIALIZEBASETEXTURE(object->baseTexture);
766 object->width = Width;
767 object->height = Height;
769 /** Non-power2 support **/
770 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
771 pow2Width = Width;
772 pow2Height = Height;
773 } else {
774 /* Find the nearest pow2 match */
775 pow2Width = pow2Height = 1;
776 while (pow2Width < Width) pow2Width <<= 1;
777 while (pow2Height < Height) pow2Height <<= 1;
780 /** FIXME: add support for real non-power-two if it's provided by the video card **/
781 /* Precalculated scaling for 'faked' non power of two texture coords */
782 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
783 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
784 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
786 /* Calculate levels for mip mapping */
787 if (Levels == 0) {
788 TRACE("calculating levels %d\n", object->baseTexture.levels);
789 object->baseTexture.levels++;
790 tmpW = Width;
791 tmpH = Height;
792 while (tmpW > 1 || tmpH > 1) {
793 tmpW = max(1, tmpW >> 1);
794 tmpH = max(1, tmpH >> 1);
795 object->baseTexture.levels++;
797 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
800 /* Generate all the surfaces */
801 tmpW = Width;
802 tmpH = Height;
803 for (i = 0; i < object->baseTexture.levels; i++)
805 /* use the callback to create the texture surface */
806 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
807 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
808 FIXME("Failed to create surface %p\n", object);
809 /* clean up */
810 object->surfaces[i] = NULL;
811 IWineD3DTexture_Release((IWineD3DTexture *)object);
813 *ppTexture = NULL;
814 return hr;
817 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
818 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
819 /* calculate the next mipmap level */
820 tmpW = max(1, tmpW >> 1);
821 tmpH = max(1, tmpH >> 1);
824 TRACE("(%p) : Created texture %p\n", This, object);
825 return WINED3D_OK;
828 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
829 UINT Width, UINT Height, UINT Depth,
830 UINT Levels, DWORD Usage,
831 WINED3DFORMAT Format, WINED3DPOOL Pool,
832 IWineD3DVolumeTexture **ppVolumeTexture,
833 HANDLE *pSharedHandle, IUnknown *parent,
834 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
837 IWineD3DVolumeTextureImpl *object;
838 unsigned int i;
839 UINT tmpW;
840 UINT tmpH;
841 UINT tmpD;
843 /* TODO: It should only be possible to create textures for formats
844 that are reported as supported */
845 if (WINED3DFMT_UNKNOWN >= Format) {
846 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
847 return WINED3DERR_INVALIDCALL;
850 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
851 D3DINITIALIZEBASETEXTURE(object->baseTexture);
853 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
854 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
856 object->width = Width;
857 object->height = Height;
858 object->depth = Depth;
860 /* Calculate levels for mip mapping */
861 if (Levels == 0) {
862 object->baseTexture.levels++;
863 tmpW = Width;
864 tmpH = Height;
865 tmpD = Depth;
866 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
869 tmpD = max(1, tmpD >> 1);
870 object->baseTexture.levels++;
872 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
875 /* Generate all the surfaces */
876 tmpW = Width;
877 tmpH = Height;
878 tmpD = Depth;
880 for (i = 0; i < object->baseTexture.levels; i++)
882 HRESULT hr;
883 /* Create the volume */
884 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
885 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
887 if(FAILED(hr)) {
888 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
889 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
890 *ppVolumeTexture = NULL;
891 return hr;
894 /* Set its container to this object */
895 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
897 /* calcualte the next mipmap level */
898 tmpW = max(1, tmpW >> 1);
899 tmpH = max(1, tmpH >> 1);
900 tmpD = max(1, tmpD >> 1);
903 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
904 TRACE("(%p) : Created volume texture %p\n", This, object);
905 return WINED3D_OK;
908 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
909 UINT Width, UINT Height, UINT Depth,
910 DWORD Usage,
911 WINED3DFORMAT Format, WINED3DPOOL Pool,
912 IWineD3DVolume** ppVolume,
913 HANDLE* pSharedHandle, IUnknown *parent) {
915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
916 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
917 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
919 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
921 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object->currentDesc.Width = Width;
925 object->currentDesc.Height = Height;
926 object->currentDesc.Depth = Depth;
927 object->bytesPerPixel = formatDesc->bpp;
929 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
930 object->lockable = TRUE;
931 object->locked = FALSE;
932 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
933 object->dirty = TRUE;
935 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
938 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
939 UINT Levels, DWORD Usage,
940 WINED3DFORMAT Format, WINED3DPOOL Pool,
941 IWineD3DCubeTexture **ppCubeTexture,
942 HANDLE *pSharedHandle, IUnknown *parent,
943 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
946 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
947 unsigned int i, j;
948 UINT tmpW;
949 HRESULT hr;
950 unsigned int pow2EdgeLength = EdgeLength;
952 /* TODO: It should only be possible to create textures for formats
953 that are reported as supported */
954 if (WINED3DFMT_UNKNOWN >= Format) {
955 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
956 return WINED3DERR_INVALIDCALL;
959 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
960 WARN("(%p) : Tried to create not supported cube texture\n", This);
961 return WINED3DERR_INVALIDCALL;
964 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
965 D3DINITIALIZEBASETEXTURE(object->baseTexture);
967 TRACE("(%p) Create Cube Texture\n", This);
969 /** Non-power2 support **/
971 /* Find the nearest pow2 match */
972 pow2EdgeLength = 1;
973 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
975 object->edgeLength = EdgeLength;
976 /* TODO: support for native non-power 2 */
977 /* Precalculated scaling for 'faked' non power of two texture coords */
978 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
980 /* Calculate levels for mip mapping */
981 if (Levels == 0) {
982 object->baseTexture.levels++;
983 tmpW = EdgeLength;
984 while (tmpW > 1) {
985 tmpW = max(1, tmpW >> 1);
986 object->baseTexture.levels++;
988 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
991 /* Generate all the surfaces */
992 tmpW = EdgeLength;
993 for (i = 0; i < object->baseTexture.levels; i++) {
995 /* Create the 6 faces */
996 for (j = 0; j < 6; j++) {
998 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
999 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1001 if(hr!= WINED3D_OK) {
1002 /* clean up */
1003 int k;
1004 int l;
1005 for (l = 0; l < j; l++) {
1006 IWineD3DSurface_Release(object->surfaces[j][i]);
1008 for (k = 0; k < i; k++) {
1009 for (l = 0; l < 6; l++) {
1010 IWineD3DSurface_Release(object->surfaces[l][j]);
1014 FIXME("(%p) Failed to create surface\n",object);
1015 HeapFree(GetProcessHeap(),0,object);
1016 *ppCubeTexture = NULL;
1017 return hr;
1019 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1020 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1022 tmpW = max(1, tmpW >> 1);
1025 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1026 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1027 return WINED3D_OK;
1030 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1032 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1033 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1035 /* Just a check to see if we support this type of query */
1036 switch(Type) {
1037 case WINED3DQUERYTYPE_OCCLUSION:
1038 TRACE("(%p) occlusion query\n", This);
1039 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1040 hr = WINED3D_OK;
1041 else
1042 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1043 break;
1045 case WINED3DQUERYTYPE_EVENT:
1046 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1047 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1048 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1050 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1052 hr = WINED3D_OK;
1053 break;
1055 case WINED3DQUERYTYPE_VCACHE:
1056 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1057 case WINED3DQUERYTYPE_VERTEXSTATS:
1058 case WINED3DQUERYTYPE_TIMESTAMP:
1059 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1060 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1061 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1062 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1063 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1064 case WINED3DQUERYTYPE_PIXELTIMINGS:
1065 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1066 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1067 default:
1068 FIXME("(%p) Unhandled query type %d\n", This, Type);
1070 if(NULL == ppQuery || hr != WINED3D_OK) {
1071 return hr;
1074 D3DCREATEOBJECTINSTANCE(object, Query)
1075 object->type = Type;
1076 /* allocated the 'extended' data based on the type of query requested */
1077 switch(Type){
1078 case WINED3DQUERYTYPE_OCCLUSION:
1079 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1080 TRACE("(%p) Allocating data for an occlusion query\n", This);
1081 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1082 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1083 break;
1085 case WINED3DQUERYTYPE_EVENT:
1086 /* TODO: GL_APPLE_fence */
1087 if(GL_SUPPORT(APPLE_FENCE)) {
1088 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1089 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1090 checkGLcall("glGenFencesAPPLE");
1091 } else if(GL_SUPPORT(NV_FENCE)) {
1092 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1093 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1094 checkGLcall("glGenFencesNV");
1096 break;
1098 case WINED3DQUERYTYPE_VCACHE:
1099 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1100 case WINED3DQUERYTYPE_VERTEXSTATS:
1101 case WINED3DQUERYTYPE_TIMESTAMP:
1102 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1103 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1104 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1105 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1106 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1107 case WINED3DQUERYTYPE_PIXELTIMINGS:
1108 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1109 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1110 default:
1111 object->extendedData = 0;
1112 FIXME("(%p) Unhandled query type %d\n",This , Type);
1114 TRACE("(%p) : Created Query %p\n", This, object);
1115 return WINED3D_OK;
1118 /*****************************************************************************
1119 * IWineD3DDeviceImpl_SetupFullscreenWindow
1121 * Helper function that modifies a HWND's Style and ExStyle for proper
1122 * fullscreen use.
1124 * Params:
1125 * iface: Pointer to the IWineD3DDevice interface
1126 * window: Window to setup
1128 *****************************************************************************/
1129 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1132 LONG style, exStyle;
1133 /* Don't do anything if an original style is stored.
1134 * That shouldn't happen
1136 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1137 if (This->style || This->exStyle) {
1138 ERR("(%p): Want to change the window parameters of HWND %p, but "
1139 "another style is stored for restoration afterwards\n", This, window);
1142 /* Get the parameters and save them */
1143 style = GetWindowLongW(window, GWL_STYLE);
1144 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1145 This->style = style;
1146 This->exStyle = exStyle;
1148 /* Filter out window decorations */
1149 style &= ~WS_CAPTION;
1150 style &= ~WS_THICKFRAME;
1151 exStyle &= ~WS_EX_WINDOWEDGE;
1152 exStyle &= ~WS_EX_CLIENTEDGE;
1154 /* Make sure the window is managed, otherwise we won't get keyboard input */
1155 style |= WS_POPUP | WS_SYSMENU;
1157 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1158 This->style, This->exStyle, style, exStyle);
1160 SetWindowLongW(window, GWL_STYLE, style);
1161 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1163 /* Inform the window about the update. */
1164 SetWindowPos(window, HWND_TOP, 0, 0,
1165 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1166 ShowWindow(window, SW_NORMAL);
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_RestoreWindow
1172 * Helper function that restores a windows' properties when taking it out
1173 * of fullscreen mode
1175 * Params:
1176 * iface: Pointer to the IWineD3DDevice interface
1177 * window: Window to setup
1179 *****************************************************************************/
1180 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1183 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1184 * switch, do nothing
1186 if (!This->style && !This->exStyle) return;
1188 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1189 This, window, This->style, This->exStyle);
1191 SetWindowLongW(window, GWL_STYLE, This->style);
1192 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1194 /* Delete the old values */
1195 This->style = 0;
1196 This->exStyle = 0;
1198 /* Inform the window about the update */
1199 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1200 0, 0, 0, 0, /* Pos, Size, ignored */
1201 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1204 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1205 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1206 IUnknown* parent,
1207 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1208 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1211 HDC hDc;
1212 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1213 HRESULT hr = WINED3D_OK;
1214 IUnknown *bufferParent;
1215 Display *display;
1217 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1219 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1220 * does a device hold a reference to a swap chain giving them a lifetime of the device
1221 * or does the swap chain notify the device of its destruction.
1222 *******************************/
1224 /* Check the params */
1225 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1226 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1227 return WINED3DERR_INVALIDCALL;
1228 } else if (pPresentationParameters->BackBufferCount > 1) {
1229 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1232 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1234 /*********************
1235 * Lookup the window Handle and the relating X window handle
1236 ********************/
1238 /* Setup hwnd we are using, plus which display this equates to */
1239 object->win_handle = pPresentationParameters->hDeviceWindow;
1240 if (!object->win_handle) {
1241 object->win_handle = This->createParms.hFocusWindow;
1244 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1245 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1246 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1247 return WINED3DERR_NOTAVAILABLE;
1249 hDc = GetDC(object->win_handle);
1250 display = get_display(hDc);
1251 ReleaseDC(object->win_handle, hDc);
1252 TRACE("Using a display of %p %p\n", display, hDc);
1254 if (NULL == display || NULL == hDc) {
1255 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1256 return WINED3DERR_NOTAVAILABLE;
1259 if (object->win == 0) {
1260 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1261 return WINED3DERR_NOTAVAILABLE;
1264 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1265 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1266 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1268 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1269 * then the corresponding dimension of the client area of the hDeviceWindow
1270 * (or the focus window, if hDeviceWindow is NULL) is taken.
1271 **********************/
1273 if (pPresentationParameters->Windowed &&
1274 ((pPresentationParameters->BackBufferWidth == 0) ||
1275 (pPresentationParameters->BackBufferHeight == 0))) {
1277 RECT Rect;
1278 GetClientRect(object->win_handle, &Rect);
1280 if (pPresentationParameters->BackBufferWidth == 0) {
1281 pPresentationParameters->BackBufferWidth = Rect.right;
1282 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1284 if (pPresentationParameters->BackBufferHeight == 0) {
1285 pPresentationParameters->BackBufferHeight = Rect.bottom;
1286 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1290 /* Put the correct figures in the presentation parameters */
1291 TRACE("Copying across presentation parameters\n");
1292 object->presentParms = *pPresentationParameters;
1294 TRACE("calling rendertarget CB\n");
1295 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1296 parent,
1297 object->presentParms.BackBufferWidth,
1298 object->presentParms.BackBufferHeight,
1299 object->presentParms.BackBufferFormat,
1300 object->presentParms.MultiSampleType,
1301 object->presentParms.MultiSampleQuality,
1302 TRUE /* Lockable */,
1303 &object->frontBuffer,
1304 NULL /* pShared (always null)*/);
1305 if (object->frontBuffer != NULL) {
1306 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1307 } else {
1308 ERR("Failed to create the front buffer\n");
1309 goto error;
1313 * Create an opengl context for the display visual
1314 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1315 * use different properties after that point in time. FIXME: How to handle when requested format
1316 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1317 * it chooses is identical to the one already being used!
1318 **********************************/
1319 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1321 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1322 if(!object->context)
1323 return E_OUTOFMEMORY;
1324 object->num_contexts = 1;
1326 ENTER_GL();
1327 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1328 LEAVE_GL();
1330 if (!object->context[0]) {
1331 ERR("Failed to create a new context\n");
1332 hr = WINED3DERR_NOTAVAILABLE;
1333 goto error;
1334 } else {
1335 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1336 object->win_handle, object->context[0]->glCtx, object->win);
1339 /*********************
1340 * Windowed / Fullscreen
1341 *******************/
1344 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1345 * so we should really check to see if there is a fullscreen swapchain already
1346 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1347 **************************************/
1349 if (!pPresentationParameters->Windowed) {
1351 DEVMODEW devmode;
1352 HDC hdc;
1353 int bpp = 0;
1354 RECT clip_rc;
1356 /* Get info on the current display setup */
1357 hdc = GetDC(0);
1358 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1359 ReleaseDC(0, hdc);
1361 /* Change the display settings */
1362 memset(&devmode, 0, sizeof(devmode));
1363 devmode.dmSize = sizeof(devmode);
1364 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1365 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1366 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1367 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1368 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1369 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1371 /* For GetDisplayMode */
1372 This->ddraw_width = devmode.dmPelsWidth;
1373 This->ddraw_height = devmode.dmPelsHeight;
1374 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1376 IWineD3DDevice_SetFullscreen(iface, TRUE);
1378 /* And finally clip mouse to our screen */
1379 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1380 ClipCursor(&clip_rc);
1383 /*********************
1384 * Create the back, front and stencil buffers
1385 *******************/
1386 if(object->presentParms.BackBufferCount > 0) {
1387 int i;
1389 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1390 if(!object->backBuffer) {
1391 ERR("Out of memory\n");
1392 hr = E_OUTOFMEMORY;
1393 goto error;
1396 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1397 TRACE("calling rendertarget CB\n");
1398 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1399 parent,
1400 object->presentParms.BackBufferWidth,
1401 object->presentParms.BackBufferHeight,
1402 object->presentParms.BackBufferFormat,
1403 object->presentParms.MultiSampleType,
1404 object->presentParms.MultiSampleQuality,
1405 TRUE /* Lockable */,
1406 &object->backBuffer[i],
1407 NULL /* pShared (always null)*/);
1408 if(hr == WINED3D_OK && object->backBuffer[i]) {
1409 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1410 } else {
1411 ERR("Cannot create new back buffer\n");
1412 goto error;
1414 ENTER_GL();
1415 glDrawBuffer(GL_BACK);
1416 checkGLcall("glDrawBuffer(GL_BACK)");
1417 LEAVE_GL();
1419 } else {
1420 object->backBuffer = NULL;
1422 /* Single buffering - draw to front buffer */
1423 ENTER_GL();
1424 glDrawBuffer(GL_FRONT);
1425 checkGLcall("glDrawBuffer(GL_FRONT)");
1426 LEAVE_GL();
1429 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1430 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1431 TRACE("Creating depth stencil buffer\n");
1432 if (This->depthStencilBuffer == NULL ) {
1433 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1434 parent,
1435 object->presentParms.BackBufferWidth,
1436 object->presentParms.BackBufferHeight,
1437 object->presentParms.AutoDepthStencilFormat,
1438 object->presentParms.MultiSampleType,
1439 object->presentParms.MultiSampleQuality,
1440 FALSE /* FIXME: Discard */,
1441 &This->depthStencilBuffer,
1442 NULL /* pShared (always null)*/ );
1443 if (This->depthStencilBuffer != NULL)
1444 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1447 /** TODO: A check on width, height and multisample types
1448 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1449 ****************************/
1450 object->wantsDepthStencilBuffer = TRUE;
1451 } else {
1452 object->wantsDepthStencilBuffer = FALSE;
1455 TRACE("Created swapchain %p\n", object);
1456 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1457 return WINED3D_OK;
1459 error:
1460 if (object->backBuffer) {
1461 int i;
1462 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1463 if(object->backBuffer[i]) {
1464 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1465 IUnknown_Release(bufferParent); /* once for the get parent */
1466 if (IUnknown_Release(bufferParent) > 0) {
1467 FIXME("(%p) Something's still holding the back buffer\n",This);
1471 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1472 object->backBuffer = NULL;
1474 if(object->context[0])
1475 DestroyContext(This, object->context[0]);
1476 if(object->frontBuffer) {
1477 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1478 IUnknown_Release(bufferParent); /* once for the get parent */
1479 if (IUnknown_Release(bufferParent) > 0) {
1480 FIXME("(%p) Something's still holding the front buffer\n",This);
1483 HeapFree(GetProcessHeap(), 0, object);
1484 return hr;
1487 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1488 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1490 TRACE("(%p)\n", This);
1492 return This->NumberOfSwapChains;
1495 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1497 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1499 if(iSwapChain < This->NumberOfSwapChains) {
1500 *pSwapChain = This->swapchains[iSwapChain];
1501 IWineD3DSwapChain_AddRef(*pSwapChain);
1502 TRACE("(%p) returning %p\n", This, *pSwapChain);
1503 return WINED3D_OK;
1504 } else {
1505 TRACE("Swapchain out of range\n");
1506 *pSwapChain = NULL;
1507 return WINED3DERR_INVALIDCALL;
1511 /*****
1512 * Vertex Declaration
1513 *****/
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1515 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1517 IWineD3DVertexDeclarationImpl *object = NULL;
1518 HRESULT hr = WINED3D_OK;
1520 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1521 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1523 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1525 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1527 return hr;
1530 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1532 unsigned int idx, idx2;
1533 unsigned int offset;
1534 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1535 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1536 BOOL has_blend_idx = has_blend &&
1537 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1538 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1539 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1540 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1541 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1542 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1543 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1545 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1546 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1548 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1549 WINED3DVERTEXELEMENT *elements = NULL;
1551 unsigned int size;
1552 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1553 if (has_blend_idx) num_blends--;
1555 /* Compute declaration size */
1556 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1557 has_psize + has_diffuse + has_specular + num_textures + 1;
1559 /* convert the declaration */
1560 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1561 if (!elements)
1562 return 0;
1564 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1565 idx = 0;
1566 if (has_pos) {
1567 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1568 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1569 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1571 else {
1572 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1573 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1575 elements[idx].UsageIndex = 0;
1576 idx++;
1578 if (has_blend && (num_blends > 0)) {
1579 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1580 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1581 else
1582 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1583 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1584 elements[idx].UsageIndex = 0;
1585 idx++;
1587 if (has_blend_idx) {
1588 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1589 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1590 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1591 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1592 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1593 else
1594 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1595 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1596 elements[idx].UsageIndex = 0;
1597 idx++;
1599 if (has_normal) {
1600 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1601 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1602 elements[idx].UsageIndex = 0;
1603 idx++;
1605 if (has_psize) {
1606 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1607 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1608 elements[idx].UsageIndex = 0;
1609 idx++;
1611 if (has_diffuse) {
1612 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1613 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1614 elements[idx].UsageIndex = 0;
1615 idx++;
1617 if (has_specular) {
1618 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1619 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1620 elements[idx].UsageIndex = 1;
1621 idx++;
1623 for (idx2 = 0; idx2 < num_textures; idx2++) {
1624 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1625 switch (numcoords) {
1626 case WINED3DFVF_TEXTUREFORMAT1:
1627 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1628 break;
1629 case WINED3DFVF_TEXTUREFORMAT2:
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1631 break;
1632 case WINED3DFVF_TEXTUREFORMAT3:
1633 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1634 break;
1635 case WINED3DFVF_TEXTUREFORMAT4:
1636 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1637 break;
1639 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1640 elements[idx].UsageIndex = idx2;
1641 idx++;
1644 /* Now compute offsets, and initialize the rest of the fields */
1645 for (idx = 0, offset = 0; idx < size-1; idx++) {
1646 elements[idx].Stream = 0;
1647 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1648 elements[idx].Offset = offset;
1649 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1652 *ppVertexElements = elements;
1653 return size;
1656 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1657 WINED3DVERTEXELEMENT* elements = NULL;
1658 size_t size;
1659 DWORD hr;
1661 size = ConvertFvfToDeclaration(Fvf, &elements);
1662 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1664 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1665 HeapFree(GetProcessHeap(), 0, elements);
1666 if (hr != S_OK) return hr;
1668 return WINED3D_OK;
1671 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1672 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1674 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1675 HRESULT hr = WINED3D_OK;
1676 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1677 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1679 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1681 if (vertex_declaration) {
1682 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1685 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1687 if (WINED3D_OK != hr) {
1688 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1689 IWineD3DVertexShader_Release(*ppVertexShader);
1690 return WINED3DERR_INVALIDCALL;
1693 return WINED3D_OK;
1696 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1698 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1699 HRESULT hr = WINED3D_OK;
1701 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1702 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1703 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1704 if (WINED3D_OK == hr) {
1705 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1706 } else {
1707 WARN("(%p) : Failed to create pixel shader\n", This);
1710 return hr;
1713 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1715 IWineD3DPaletteImpl *object;
1716 HRESULT hr;
1717 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1719 /* Create the new object */
1720 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1721 if(!object) {
1722 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1723 return E_OUTOFMEMORY;
1726 object->lpVtbl = &IWineD3DPalette_Vtbl;
1727 object->ref = 1;
1728 object->Flags = Flags;
1729 object->parent = Parent;
1730 object->wineD3DDevice = This;
1731 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1733 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1735 if(!object->hpal) {
1736 HeapFree( GetProcessHeap(), 0, object);
1737 return E_OUTOFMEMORY;
1740 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1741 if(FAILED(hr)) {
1742 IWineD3DPalette_Release((IWineD3DPalette *) object);
1743 return hr;
1746 *Palette = (IWineD3DPalette *) object;
1748 return WINED3D_OK;
1751 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1753 IWineD3DSwapChainImpl *swapchain;
1754 HRESULT hr;
1755 DWORD state;
1757 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1758 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1760 /* TODO: Test if OpenGL is compiled in and loaded */
1762 TRACE("(%p) : Creating stateblock\n", This);
1763 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1764 hr = IWineD3DDevice_CreateStateBlock(iface,
1765 WINED3DSBT_INIT,
1766 (IWineD3DStateBlock **)&This->stateBlock,
1767 NULL);
1768 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1769 WARN("Failed to create stateblock\n");
1770 return hr;
1772 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1773 This->updateStateBlock = This->stateBlock;
1774 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1776 hr = allocate_shader_constants(This->updateStateBlock);
1777 if (WINED3D_OK != hr)
1778 return hr;
1780 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1781 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1782 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1784 /* Initialize the texture unit mapping to a 1:1 mapping */
1785 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1786 if (state < GL_LIMITS(fragment_samplers)) {
1787 This->texUnitMap[state] = state;
1788 This->rev_tex_unit_map[state] = state;
1789 } else {
1790 This->texUnitMap[state] = -1;
1791 This->rev_tex_unit_map[state] = -1;
1795 /* Setup the implicit swapchain */
1796 TRACE("Creating implicit swapchain\n");
1797 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1798 if (FAILED(hr) || !swapchain) {
1799 WARN("Failed to create implicit swapchain\n");
1800 return hr;
1803 This->NumberOfSwapChains = 1;
1804 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1805 if(!This->swapchains) {
1806 ERR("Out of memory!\n");
1807 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1808 return E_OUTOFMEMORY;
1810 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1812 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1814 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1815 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1816 This->render_targets[0] = swapchain->backBuffer[0];
1817 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1819 else {
1820 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1821 This->render_targets[0] = swapchain->frontBuffer;
1822 This->lastActiveRenderTarget = swapchain->frontBuffer;
1824 IWineD3DSurface_AddRef(This->render_targets[0]);
1825 This->activeContext = swapchain->context[0];
1826 This->lastThread = GetCurrentThreadId();
1828 /* Depth Stencil support */
1829 This->stencilBufferTarget = This->depthStencilBuffer;
1830 if (NULL != This->stencilBufferTarget) {
1831 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1834 /* Set up some starting GL setup */
1835 ENTER_GL();
1837 /* Setup all the devices defaults */
1838 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1839 #if 0
1840 IWineD3DImpl_CheckGraphicsMemory();
1841 #endif
1843 { /* Set a default viewport */
1844 WINED3DVIEWPORT vp;
1845 vp.X = 0;
1846 vp.Y = 0;
1847 vp.Width = pPresentationParameters->BackBufferWidth;
1848 vp.Height = pPresentationParameters->BackBufferHeight;
1849 vp.MinZ = 0.0f;
1850 vp.MaxZ = 1.0f;
1851 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1854 /* Initialize the current view state */
1855 This->view_ident = 1;
1856 This->contexts[0]->last_was_rhw = 0;
1857 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1858 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1860 switch(wined3d_settings.offscreen_rendering_mode) {
1861 case ORM_FBO:
1862 case ORM_PBUFFER:
1863 This->offscreenBuffer = GL_BACK;
1864 break;
1866 case ORM_BACKBUFFER:
1868 if(GL_LIMITS(aux_buffers) > 0) {
1869 TRACE("Using auxilliary buffer for offscreen rendering\n");
1870 This->offscreenBuffer = GL_AUX0;
1871 } else {
1872 TRACE("Using back buffer for offscreen rendering\n");
1873 This->offscreenBuffer = GL_BACK;
1878 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1879 LEAVE_GL();
1881 /* Clear the screen */
1882 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1883 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1884 0x00, 1.0, 0);
1886 This->d3d_initialized = TRUE;
1887 return WINED3D_OK;
1890 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1892 int sampler;
1893 uint i;
1894 TRACE("(%p)\n", This);
1896 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1898 ENTER_GL();
1899 /* I don't think that the interface guarants that the device is destroyed from the same thread
1900 * it was created. Thus make sure a context is active for the glDelete* calls
1902 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1903 LEAVE_GL();
1905 TRACE("Deleting high order patches\n");
1906 for(i = 0; i < PATCHMAP_SIZE; i++) {
1907 struct list *e1, *e2;
1908 struct WineD3DRectPatch *patch;
1909 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1910 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1911 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1915 /* Delete the pbuffer context if there is any */
1916 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1918 /* Delete the mouse cursor texture */
1919 if(This->cursorTexture) {
1920 ENTER_GL();
1921 glDeleteTextures(1, &This->cursorTexture);
1922 LEAVE_GL();
1923 This->cursorTexture = 0;
1926 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1927 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1929 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1930 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1933 /* Release the buffers (with sanity checks)*/
1934 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1935 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1936 if(This->depthStencilBuffer != This->stencilBufferTarget)
1937 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1939 This->stencilBufferTarget = NULL;
1941 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1942 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1943 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1945 TRACE("Setting rendertarget to NULL\n");
1946 This->render_targets[0] = NULL;
1948 if (This->depthStencilBuffer) {
1949 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1950 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1952 This->depthStencilBuffer = NULL;
1955 for(i=0; i < This->NumberOfSwapChains; i++) {
1956 TRACE("Releasing the implicit swapchain %d\n", i);
1957 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1958 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1962 HeapFree(GetProcessHeap(), 0, This->swapchains);
1963 This->swapchains = NULL;
1964 This->NumberOfSwapChains = 0;
1966 /* Release the update stateblock */
1967 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1968 if(This->updateStateBlock != This->stateBlock)
1969 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1971 This->updateStateBlock = NULL;
1973 { /* because were not doing proper internal refcounts releasing the primary state block
1974 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1975 to set this->stateBlock = NULL; first */
1976 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1977 This->stateBlock = NULL;
1979 /* Release the stateblock */
1980 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1981 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1985 HeapFree(GetProcessHeap(), 0, This->render_targets);
1986 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
1987 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1988 This->render_targets = NULL;
1989 This->fbo_color_attachments = NULL;
1990 This->draw_buffers = NULL;
1993 This->d3d_initialized = FALSE;
1994 return WINED3D_OK;
1997 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1999 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2001 /* Setup the window for fullscreen mode */
2002 if(fullscreen && !This->ddraw_fullscreen) {
2003 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2004 } else if(!fullscreen && This->ddraw_fullscreen) {
2005 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2008 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2009 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2010 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2011 * separately.
2013 This->ddraw_fullscreen = fullscreen;
2016 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2017 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2018 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2020 * There is no way to deactivate thread safety once it is enabled
2022 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2025 /*For now just store the flag(needed in case of ddraw) */
2026 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2028 return;
2031 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2032 DEVMODEW devmode;
2033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2034 LONG ret;
2035 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2036 RECT clip_rc;
2038 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2040 /* Resize the screen even without a window:
2041 * The app could have unset it with SetCooperativeLevel, but not called
2042 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2043 * but we don't have any hwnd
2046 memset(&devmode, 0, sizeof(devmode));
2047 devmode.dmSize = sizeof(devmode);
2048 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2049 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2050 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2051 devmode.dmPelsWidth = pMode->Width;
2052 devmode.dmPelsHeight = pMode->Height;
2054 devmode.dmDisplayFrequency = pMode->RefreshRate;
2055 if (pMode->RefreshRate != 0) {
2056 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2059 /* Only change the mode if necessary */
2060 if( (This->ddraw_width == pMode->Width) &&
2061 (This->ddraw_height == pMode->Height) &&
2062 (This->ddraw_format == pMode->Format) &&
2063 (pMode->RefreshRate == 0) ) {
2064 return WINED3D_OK;
2067 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2068 if (ret != DISP_CHANGE_SUCCESSFUL) {
2069 if(devmode.dmDisplayFrequency != 0) {
2070 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2071 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2072 devmode.dmDisplayFrequency = 0;
2073 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2075 if(ret != DISP_CHANGE_SUCCESSFUL) {
2076 return WINED3DERR_NOTAVAILABLE;
2080 /* Store the new values */
2081 This->ddraw_width = pMode->Width;
2082 This->ddraw_height = pMode->Height;
2083 This->ddraw_format = pMode->Format;
2085 /* Only do this with a window of course */
2086 if(This->ddraw_window)
2087 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2089 /* And finally clip mouse to our screen */
2090 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2091 ClipCursor(&clip_rc);
2093 return WINED3D_OK;
2096 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2098 *ppD3D= This->wineD3D;
2099 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2100 IWineD3D_AddRef(*ppD3D);
2101 return WINED3D_OK;
2104 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2105 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2106 * into the video ram as possible and seeing how many fit
2107 * you can also get the correct initial value from nvidia and ATI's driver via X
2108 * texture memory is video memory + AGP memory
2109 *******************/
2110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2111 static BOOL showfixmes = TRUE;
2112 if (showfixmes) {
2113 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2114 (wined3d_settings.emulated_textureram/(1024*1024)),
2115 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2116 showfixmes = FALSE;
2118 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2119 (wined3d_settings.emulated_textureram/(1024*1024)),
2120 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2121 /* return simulated texture memory left */
2122 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2127 /*****
2128 * Get / Set FVF
2129 *****/
2130 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 /* Update the current state block */
2134 This->updateStateBlock->changed.fvf = TRUE;
2135 This->updateStateBlock->set.fvf = TRUE;
2137 if(This->updateStateBlock->fvf == fvf) {
2138 TRACE("Application is setting the old fvf over, nothing to do\n");
2139 return WINED3D_OK;
2142 This->updateStateBlock->fvf = fvf;
2143 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2145 return WINED3D_OK;
2149 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2151 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2152 *pfvf = This->stateBlock->fvf;
2153 return WINED3D_OK;
2156 /*****
2157 * Get / Set Stream Source
2158 *****/
2159 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2161 IWineD3DVertexBuffer *oldSrc;
2163 if (StreamNumber >= MAX_STREAMS) {
2164 WARN("Stream out of range %d\n", StreamNumber);
2165 return WINED3DERR_INVALIDCALL;
2168 oldSrc = This->stateBlock->streamSource[StreamNumber];
2169 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2171 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2172 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2174 if(oldSrc == pStreamData &&
2175 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2176 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2177 TRACE("Application is setting the old values over, nothing to do\n");
2178 return WINED3D_OK;
2181 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2182 if (pStreamData) {
2183 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2184 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2187 /* Handle recording of state blocks */
2188 if (This->isRecordingState) {
2189 TRACE("Recording... not performing anything\n");
2190 return WINED3D_OK;
2193 /* Need to do a getParent and pass the reffs up */
2194 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2195 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2196 so for now, just count internally */
2197 if (pStreamData != NULL) {
2198 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2199 InterlockedIncrement(&vbImpl->bindCount);
2201 if (oldSrc != NULL) {
2202 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2207 return WINED3D_OK;
2210 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2213 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2214 This->stateBlock->streamSource[StreamNumber],
2215 This->stateBlock->streamOffset[StreamNumber],
2216 This->stateBlock->streamStride[StreamNumber]);
2218 if (StreamNumber >= MAX_STREAMS) {
2219 WARN("Stream out of range %d\n", StreamNumber);
2220 return WINED3DERR_INVALIDCALL;
2222 *pStream = This->stateBlock->streamSource[StreamNumber];
2223 *pStride = This->stateBlock->streamStride[StreamNumber];
2224 if (pOffset) {
2225 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2228 if (*pStream != NULL) {
2229 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2231 return WINED3D_OK;
2234 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2236 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2237 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2239 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2240 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2242 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2243 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2244 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2246 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2247 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2251 return WINED3D_OK;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2257 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2258 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2260 TRACE("(%p) : returning %d\n", This, *Divider);
2262 return WINED3D_OK;
2265 /*****
2266 * Get / Set & Multiply Transform
2267 *****/
2268 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2271 /* Most of this routine, comments included copied from ddraw tree initially: */
2272 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2274 /* Handle recording of state blocks */
2275 if (This->isRecordingState) {
2276 TRACE("Recording... not performing anything\n");
2277 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2278 This->updateStateBlock->set.transform[d3dts] = TRUE;
2279 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2280 return WINED3D_OK;
2284 * If the new matrix is the same as the current one,
2285 * we cut off any further processing. this seems to be a reasonable
2286 * optimization because as was noticed, some apps (warcraft3 for example)
2287 * tend towards setting the same matrix repeatedly for some reason.
2289 * From here on we assume that the new matrix is different, wherever it matters.
2291 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2292 TRACE("The app is setting the same matrix over again\n");
2293 return WINED3D_OK;
2294 } else {
2295 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2299 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2300 where ViewMat = Camera space, WorldMat = world space.
2302 In OpenGL, camera and world space is combined into GL_MODELVIEW
2303 matrix. The Projection matrix stay projection matrix.
2306 /* Capture the times we can just ignore the change for now */
2307 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2308 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2309 /* Handled by the state manager */
2312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2313 return WINED3D_OK;
2316 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2318 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2319 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2320 return WINED3D_OK;
2323 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2324 WINED3DMATRIX *mat = NULL;
2325 WINED3DMATRIX temp;
2327 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2328 * below means it will be recorded in a state block change, but it
2329 * works regardless where it is recorded.
2330 * If this is found to be wrong, change to StateBlock.
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2335 if (State < HIGHEST_TRANSFORMSTATE)
2337 mat = &This->updateStateBlock->transforms[State];
2338 } else {
2339 FIXME("Unhandled transform state!!\n");
2342 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2344 /* Apply change via set transform - will reapply to eg. lights this way */
2345 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2348 /*****
2349 * Get / Set Light
2350 *****/
2351 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2352 you can reference any indexes you want as long as that number max are enabled at any
2353 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2354 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2355 but when recording, just build a chain pretty much of commands to be replayed. */
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2358 float rho;
2359 PLIGHTINFOEL *object = NULL;
2360 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2361 struct list *e;
2363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2364 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2366 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2367 * the gl driver.
2369 if(!pLight) {
2370 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2371 return WINED3DERR_INVALIDCALL;
2374 switch(pLight->Type) {
2375 case WINED3DLIGHT_POINT:
2376 case WINED3DLIGHT_SPOT:
2377 case WINED3DLIGHT_PARALLELPOINT:
2378 case WINED3DLIGHT_GLSPOT:
2379 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2380 * most wanted
2382 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2383 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2384 return WINED3DERR_INVALIDCALL;
2386 break;
2388 case WINED3DLIGHT_DIRECTIONAL:
2389 /* Ignores attenuation */
2390 break;
2392 default:
2393 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2394 return WINED3DERR_INVALIDCALL;
2397 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2398 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2399 if(object->OriginalIndex == Index) break;
2400 object = NULL;
2403 if(!object) {
2404 TRACE("Adding new light\n");
2405 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2406 if(!object) {
2407 ERR("Out of memory error when allocating a light\n");
2408 return E_OUTOFMEMORY;
2410 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2411 object->glIndex = -1;
2412 object->OriginalIndex = Index;
2413 object->changed = TRUE;
2416 /* Initialize the object */
2417 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2418 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2419 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2420 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2421 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2422 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2423 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2425 /* Save away the information */
2426 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2428 switch (pLight->Type) {
2429 case WINED3DLIGHT_POINT:
2430 /* Position */
2431 object->lightPosn[0] = pLight->Position.x;
2432 object->lightPosn[1] = pLight->Position.y;
2433 object->lightPosn[2] = pLight->Position.z;
2434 object->lightPosn[3] = 1.0f;
2435 object->cutoff = 180.0f;
2436 /* FIXME: Range */
2437 break;
2439 case WINED3DLIGHT_DIRECTIONAL:
2440 /* Direction */
2441 object->lightPosn[0] = -pLight->Direction.x;
2442 object->lightPosn[1] = -pLight->Direction.y;
2443 object->lightPosn[2] = -pLight->Direction.z;
2444 object->lightPosn[3] = 0.0;
2445 object->exponent = 0.0f;
2446 object->cutoff = 180.0f;
2447 break;
2449 case WINED3DLIGHT_SPOT:
2450 /* Position */
2451 object->lightPosn[0] = pLight->Position.x;
2452 object->lightPosn[1] = pLight->Position.y;
2453 object->lightPosn[2] = pLight->Position.z;
2454 object->lightPosn[3] = 1.0;
2456 /* Direction */
2457 object->lightDirn[0] = pLight->Direction.x;
2458 object->lightDirn[1] = pLight->Direction.y;
2459 object->lightDirn[2] = pLight->Direction.z;
2460 object->lightDirn[3] = 1.0;
2463 * opengl-ish and d3d-ish spot lights use too different models for the
2464 * light "intensity" as a function of the angle towards the main light direction,
2465 * so we only can approximate very roughly.
2466 * however spot lights are rather rarely used in games (if ever used at all).
2467 * furthermore if still used, probably nobody pays attention to such details.
2469 if (pLight->Falloff == 0) {
2470 rho = 6.28f;
2471 } else {
2472 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2474 if (rho < 0.0001) rho = 0.0001f;
2475 object->exponent = -0.3/log(cos(rho/2));
2476 if (object->exponent > 128.0) {
2477 object->exponent = 128.0;
2479 object->cutoff = pLight->Phi*90/M_PI;
2481 /* FIXME: Range */
2482 break;
2484 default:
2485 FIXME("Unrecognized light type %d\n", pLight->Type);
2488 /* Update the live definitions if the light is currently assigned a glIndex */
2489 if (object->glIndex != -1 && !This->isRecordingState) {
2490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2492 return WINED3D_OK;
2495 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2496 PLIGHTINFOEL *lightInfo = NULL;
2497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2498 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2499 struct list *e;
2500 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2502 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2503 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2504 if(lightInfo->OriginalIndex == Index) break;
2505 lightInfo = NULL;
2508 if (lightInfo == NULL) {
2509 TRACE("Light information requested but light not defined\n");
2510 return WINED3DERR_INVALIDCALL;
2513 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2514 return WINED3D_OK;
2517 /*****
2518 * Get / Set Light Enable
2519 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2520 *****/
2521 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2522 PLIGHTINFOEL *lightInfo = NULL;
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2524 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2525 struct list *e;
2526 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2528 /* Tests show true = 128...not clear why */
2529 Enable = Enable? 128: 0;
2531 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2532 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2533 if(lightInfo->OriginalIndex == Index) break;
2534 lightInfo = NULL;
2536 TRACE("Found light: %p\n", lightInfo);
2538 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2539 if (lightInfo == NULL) {
2541 TRACE("Light enabled requested but light not defined, so defining one!\n");
2542 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2544 /* Search for it again! Should be fairly quick as near head of list */
2545 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2546 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2547 if(lightInfo->OriginalIndex == Index) break;
2548 lightInfo = NULL;
2550 if (lightInfo == NULL) {
2551 FIXME("Adding default lights has failed dismally\n");
2552 return WINED3DERR_INVALIDCALL;
2556 lightInfo->enabledChanged = TRUE;
2557 if(!Enable) {
2558 if(lightInfo->glIndex != -1) {
2559 if(!This->isRecordingState) {
2560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2563 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2564 lightInfo->glIndex = -1;
2565 } else {
2566 TRACE("Light already disabled, nothing to do\n");
2568 } else {
2569 if (lightInfo->glIndex != -1) {
2570 /* nop */
2571 TRACE("Nothing to do as light was enabled\n");
2572 } else {
2573 int i;
2574 /* Find a free gl light */
2575 for(i = 0; i < This->maxConcurrentLights; i++) {
2576 if(This->stateBlock->activeLights[i] == NULL) {
2577 This->stateBlock->activeLights[i] = lightInfo;
2578 lightInfo->glIndex = i;
2579 break;
2582 if(lightInfo->glIndex == -1) {
2583 ERR("Too many concurrently active lights\n");
2584 return WINED3DERR_INVALIDCALL;
2587 /* i == lightInfo->glIndex */
2588 if(!This->isRecordingState) {
2589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2594 return WINED3D_OK;
2597 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2599 PLIGHTINFOEL *lightInfo = NULL;
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 struct list *e;
2602 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2603 TRACE("(%p) : for idx(%d)\n", This, Index);
2605 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2606 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2607 if(lightInfo->OriginalIndex == Index) break;
2608 lightInfo = NULL;
2611 if (lightInfo == NULL) {
2612 TRACE("Light enabled state requested but light not defined\n");
2613 return WINED3DERR_INVALIDCALL;
2615 /* true is 128 according to SetLightEnable */
2616 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2617 return WINED3D_OK;
2620 /*****
2621 * Get / Set Clip Planes
2622 *****/
2623 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2627 /* Validate Index */
2628 if (Index >= GL_LIMITS(clipplanes)) {
2629 TRACE("Application has requested clipplane this device doesn't support\n");
2630 return WINED3DERR_INVALIDCALL;
2633 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2634 This->updateStateBlock->set.clipplane[Index] = TRUE;
2636 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2637 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2638 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2639 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2640 TRACE("Application is setting old values over, nothing to do\n");
2641 return WINED3D_OK;
2644 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2645 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2646 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2647 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2649 /* Handle recording of state blocks */
2650 if (This->isRecordingState) {
2651 TRACE("Recording... not performing anything\n");
2652 return WINED3D_OK;
2655 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2657 return WINED3D_OK;
2660 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 TRACE("(%p) : for idx %d\n", This, Index);
2664 /* Validate Index */
2665 if (Index >= GL_LIMITS(clipplanes)) {
2666 TRACE("Application has requested clipplane this device doesn't support\n");
2667 return WINED3DERR_INVALIDCALL;
2670 pPlane[0] = This->stateBlock->clipplane[Index][0];
2671 pPlane[1] = This->stateBlock->clipplane[Index][1];
2672 pPlane[2] = This->stateBlock->clipplane[Index][2];
2673 pPlane[3] = This->stateBlock->clipplane[Index][3];
2674 return WINED3D_OK;
2677 /*****
2678 * Get / Set Clip Plane Status
2679 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2680 *****/
2681 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 FIXME("(%p) : stub\n", This);
2684 if (NULL == pClipStatus) {
2685 return WINED3DERR_INVALIDCALL;
2687 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2688 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2689 return WINED3D_OK;
2692 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2694 FIXME("(%p) : stub\n", This);
2695 if (NULL == pClipStatus) {
2696 return WINED3DERR_INVALIDCALL;
2698 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2699 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2700 return WINED3D_OK;
2703 /*****
2704 * Get / Set Material
2705 *****/
2706 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2709 This->updateStateBlock->changed.material = TRUE;
2710 This->updateStateBlock->set.material = TRUE;
2711 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2713 /* Handle recording of state blocks */
2714 if (This->isRecordingState) {
2715 TRACE("Recording... not performing anything\n");
2716 return WINED3D_OK;
2719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2720 return WINED3D_OK;
2723 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2725 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2726 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2727 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2728 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2729 pMaterial->Ambient.b, pMaterial->Ambient.a);
2730 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2731 pMaterial->Specular.b, pMaterial->Specular.a);
2732 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2733 pMaterial->Emissive.b, pMaterial->Emissive.a);
2734 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2736 return WINED3D_OK;
2739 /*****
2740 * Get / Set Indices
2741 *****/
2742 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2744 IWineD3DIndexBuffer *oldIdxs;
2746 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2747 oldIdxs = This->updateStateBlock->pIndexData;
2749 This->updateStateBlock->changed.indices = TRUE;
2750 This->updateStateBlock->set.indices = TRUE;
2751 This->updateStateBlock->pIndexData = pIndexData;
2753 /* Handle recording of state blocks */
2754 if (This->isRecordingState) {
2755 TRACE("Recording... not performing anything\n");
2756 return WINED3D_OK;
2759 if(oldIdxs != pIndexData) {
2760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2762 return WINED3D_OK;
2765 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 *ppIndexData = This->stateBlock->pIndexData;
2770 /* up ref count on ppindexdata */
2771 if (*ppIndexData) {
2772 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2773 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2774 }else{
2775 TRACE("(%p) No index data set\n", This);
2777 TRACE("Returning %p\n", *ppIndexData);
2779 return WINED3D_OK;
2782 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2783 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 TRACE("(%p)->(%d)\n", This, BaseIndex);
2787 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2788 TRACE("Application is setting the old value over, nothing to do\n");
2789 return WINED3D_OK;
2792 This->updateStateBlock->baseVertexIndex = BaseIndex;
2794 if (This->isRecordingState) {
2795 TRACE("Recording... not performing anything\n");
2796 return WINED3D_OK;
2798 /* The base vertex index affects the stream sources */
2799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2800 return WINED3D_OK;
2803 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 TRACE("(%p) : base_index %p\n", This, base_index);
2807 *base_index = This->stateBlock->baseVertexIndex;
2809 TRACE("Returning %u\n", *base_index);
2811 return WINED3D_OK;
2814 /*****
2815 * Get / Set Viewports
2816 *****/
2817 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2820 TRACE("(%p)\n", This);
2821 This->updateStateBlock->changed.viewport = TRUE;
2822 This->updateStateBlock->set.viewport = TRUE;
2823 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2825 /* Handle recording of state blocks */
2826 if (This->isRecordingState) {
2827 TRACE("Recording... not performing anything\n");
2828 return WINED3D_OK;
2831 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2832 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2835 return WINED3D_OK;
2839 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2841 TRACE("(%p)\n", This);
2842 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2843 return WINED3D_OK;
2846 /*****
2847 * Get / Set Render States
2848 * TODO: Verify against dx9 definitions
2849 *****/
2850 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 DWORD oldValue = This->stateBlock->renderState[State];
2855 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2857 This->updateStateBlock->changed.renderState[State] = TRUE;
2858 This->updateStateBlock->set.renderState[State] = TRUE;
2859 This->updateStateBlock->renderState[State] = Value;
2861 /* Handle recording of state blocks */
2862 if (This->isRecordingState) {
2863 TRACE("Recording... not performing anything\n");
2864 return WINED3D_OK;
2867 /* Compared here and not before the assignment to allow proper stateblock recording */
2868 if(Value == oldValue) {
2869 TRACE("Application is setting the old value over, nothing to do\n");
2870 } else {
2871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2874 return WINED3D_OK;
2877 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2879 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2880 *pValue = This->stateBlock->renderState[State];
2881 return WINED3D_OK;
2884 /*****
2885 * Get / Set Sampler States
2886 * TODO: Verify against dx9 definitions
2887 *****/
2889 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2891 DWORD oldValue;
2893 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2894 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2896 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2897 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2901 * SetSampler is designed to allow for more than the standard up to 8 textures
2902 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2903 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2905 * http://developer.nvidia.com/object/General_FAQ.html#t6
2907 * There are two new settings for GForce
2908 * the sampler one:
2909 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2910 * and the texture one:
2911 * GL_MAX_TEXTURE_COORDS_ARB.
2912 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2913 ******************/
2915 oldValue = This->stateBlock->samplerState[Sampler][Type];
2916 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2917 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2918 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2920 /* Handle recording of state blocks */
2921 if (This->isRecordingState) {
2922 TRACE("Recording... not performing anything\n");
2923 return WINED3D_OK;
2926 if(oldValue == Value) {
2927 TRACE("Application is setting the old value over, nothing to do\n");
2928 return WINED3D_OK;
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2939 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2940 This, Sampler, debug_d3dsamplerstate(Type), Type);
2942 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2943 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2946 *Value = This->stateBlock->samplerState[Sampler][Type];
2947 TRACE("(%p) : Returning %#x\n", This, *Value);
2949 return WINED3D_OK;
2952 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2955 This->updateStateBlock->set.scissorRect = TRUE;
2956 This->updateStateBlock->changed.scissorRect = TRUE;
2957 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2958 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2959 return WINED3D_OK;
2961 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2963 if(This->isRecordingState) {
2964 TRACE("Recording... not performing anything\n");
2965 return WINED3D_OK;
2968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2970 return WINED3D_OK;
2973 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2976 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2977 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2978 return WINED3D_OK;
2981 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2983 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2985 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2987 This->updateStateBlock->vertexDecl = pDecl;
2988 This->updateStateBlock->changed.vertexDecl = TRUE;
2989 This->updateStateBlock->set.vertexDecl = TRUE;
2991 if (This->isRecordingState) {
2992 TRACE("Recording... not performing anything\n");
2993 return WINED3D_OK;
2994 } else if(pDecl == oldDecl) {
2995 /* Checked after the assignment to allow proper stateblock recording */
2996 TRACE("Application is setting the old declaration over, nothing to do\n");
2997 return WINED3D_OK;
3000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3001 return WINED3D_OK;
3004 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3009 *ppDecl = This->stateBlock->vertexDecl;
3010 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3016 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3018 This->updateStateBlock->vertexShader = pShader;
3019 This->updateStateBlock->changed.vertexShader = TRUE;
3020 This->updateStateBlock->set.vertexShader = TRUE;
3022 if (This->isRecordingState) {
3023 TRACE("Recording... not performing anything\n");
3024 return WINED3D_OK;
3025 } else if(oldShader == pShader) {
3026 /* Checked here to allow proper stateblock recording */
3027 TRACE("App is setting the old shader over, nothing to do\n");
3028 return WINED3D_OK;
3031 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3033 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3035 return WINED3D_OK;
3038 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 if (NULL == ppShader) {
3042 return WINED3DERR_INVALIDCALL;
3044 *ppShader = This->stateBlock->vertexShader;
3045 if( NULL != *ppShader)
3046 IWineD3DVertexShader_AddRef(*ppShader);
3048 TRACE("(%p) : returning %p\n", This, *ppShader);
3049 return WINED3D_OK;
3052 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3053 IWineD3DDevice *iface,
3054 UINT start,
3055 CONST BOOL *srcData,
3056 UINT count) {
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 int i, cnt = min(count, MAX_CONST_B - start);
3061 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3062 iface, srcData, start, count);
3064 if (srcData == NULL || cnt < 0)
3065 return WINED3DERR_INVALIDCALL;
3067 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3068 for (i = 0; i < cnt; i++)
3069 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3071 for (i = start; i < cnt + start; ++i) {
3072 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3073 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3078 return WINED3D_OK;
3081 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3082 IWineD3DDevice *iface,
3083 UINT start,
3084 BOOL *dstData,
3085 UINT count) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 int cnt = min(count, MAX_CONST_B - start);
3090 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3091 iface, dstData, start, count);
3093 if (dstData == NULL || cnt < 0)
3094 return WINED3DERR_INVALIDCALL;
3096 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3097 return WINED3D_OK;
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3101 IWineD3DDevice *iface,
3102 UINT start,
3103 CONST int *srcData,
3104 UINT count) {
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3107 int i, cnt = min(count, MAX_CONST_I - start);
3109 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3110 iface, srcData, start, count);
3112 if (srcData == NULL || cnt < 0)
3113 return WINED3DERR_INVALIDCALL;
3115 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3116 for (i = 0; i < cnt; i++)
3117 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3118 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3120 for (i = start; i < cnt + start; ++i) {
3121 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3122 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3127 return WINED3D_OK;
3130 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3131 IWineD3DDevice *iface,
3132 UINT start,
3133 int *dstData,
3134 UINT count) {
3136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3137 int cnt = min(count, MAX_CONST_I - start);
3139 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3140 iface, dstData, start, count);
3142 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3143 return WINED3DERR_INVALIDCALL;
3145 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3146 return WINED3D_OK;
3149 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3150 IWineD3DDevice *iface,
3151 UINT start,
3152 CONST float *srcData,
3153 UINT count) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 int i;
3158 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3159 iface, srcData, start, count);
3161 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3162 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3163 return WINED3DERR_INVALIDCALL;
3165 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3166 if(TRACE_ON(d3d)) {
3167 for (i = 0; i < count; i++)
3168 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3169 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3172 for (i = start; i < count + start; ++i) {
3173 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3174 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3175 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3176 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3177 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3179 ptr->idx[ptr->count++] = i;
3180 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3182 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3191 IWineD3DDevice *iface,
3192 UINT start,
3193 float *dstData,
3194 UINT count) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3199 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3200 iface, dstData, start, count);
3202 if (dstData == NULL || cnt < 0)
3203 return WINED3DERR_INVALIDCALL;
3205 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3206 return WINED3D_OK;
3209 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3210 DWORD i;
3211 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3216 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3217 int i = This->rev_tex_unit_map[unit];
3218 int j = This->texUnitMap[stage];
3220 This->texUnitMap[stage] = unit;
3221 if (i != -1 && i != stage) {
3222 This->texUnitMap[i] = -1;
3225 This->rev_tex_unit_map[unit] = stage;
3226 if (j != -1 && j != unit) {
3227 This->rev_tex_unit_map[j] = -1;
3231 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3232 int i;
3234 for (i = 0; i < MAX_TEXTURES; ++i) {
3235 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3236 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3237 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3238 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3239 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3240 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3241 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3242 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3244 if (color_op == WINED3DTOP_DISABLE) {
3245 /* Not used, and disable higher stages */
3246 while (i < MAX_TEXTURES) {
3247 This->fixed_function_usage_map[i] = FALSE;
3248 ++i;
3250 break;
3253 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3254 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3255 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3256 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3257 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3258 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3259 This->fixed_function_usage_map[i] = TRUE;
3260 } else {
3261 This->fixed_function_usage_map[i] = FALSE;
3264 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3265 This->fixed_function_usage_map[i+1] = TRUE;
3270 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3271 int i, tex;
3273 device_update_fixed_function_usage_map(This);
3275 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3276 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3277 if (!This->fixed_function_usage_map[i]) continue;
3279 if (This->texUnitMap[i] != i) {
3280 device_map_stage(This, i, i);
3281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3282 markTextureStagesDirty(This, i);
3285 return;
3288 /* Now work out the mapping */
3289 tex = 0;
3290 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3291 if (!This->fixed_function_usage_map[i]) continue;
3293 if (This->texUnitMap[i] != tex) {
3294 device_map_stage(This, i, tex);
3295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3296 markTextureStagesDirty(This, i);
3299 ++tex;
3303 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3304 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3305 int i;
3307 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3308 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3309 device_map_stage(This, i, i);
3310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3311 if (i < MAX_TEXTURES) {
3312 markTextureStagesDirty(This, i);
3318 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3319 int current_mapping = This->rev_tex_unit_map[unit];
3321 if (current_mapping == -1) {
3322 /* Not currently used */
3323 return TRUE;
3326 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3327 /* Used by a fragment sampler */
3329 if (!pshader_sampler_tokens) {
3330 /* No pixel shader, check fixed function */
3331 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3334 /* Pixel shader, check the shader's sampler map */
3335 return !pshader_sampler_tokens[current_mapping];
3338 /* Used by a vertex sampler */
3339 return !vshader_sampler_tokens[current_mapping];
3342 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3343 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3344 DWORD *pshader_sampler_tokens = NULL;
3345 int start = GL_LIMITS(combined_samplers) - 1;
3346 int i;
3348 if (ps) {
3349 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3351 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3352 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3353 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3356 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3357 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3358 if (vshader_sampler_tokens[i]) {
3359 if (This->texUnitMap[vsampler_idx] != -1) {
3360 /* Already mapped somewhere */
3361 continue;
3364 while (start >= 0) {
3365 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3366 device_map_stage(This, vsampler_idx, start);
3367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3369 --start;
3370 break;
3373 --start;
3379 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3380 BOOL vs = use_vs(This);
3381 BOOL ps = use_ps(This);
3383 * Rules are:
3384 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3385 * that would be really messy and require shader recompilation
3386 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3387 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3389 if (ps) {
3390 device_map_psamplers(This);
3391 } else {
3392 device_map_fixed_function_samplers(This);
3395 if (vs) {
3396 device_map_vsamplers(This, ps);
3400 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3402 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3403 This->updateStateBlock->pixelShader = pShader;
3404 This->updateStateBlock->changed.pixelShader = TRUE;
3405 This->updateStateBlock->set.pixelShader = TRUE;
3407 /* Handle recording of state blocks */
3408 if (This->isRecordingState) {
3409 TRACE("Recording... not performing anything\n");
3412 if (This->isRecordingState) {
3413 TRACE("Recording... not performing anything\n");
3414 return WINED3D_OK;
3417 if(pShader == oldShader) {
3418 TRACE("App is setting the old pixel shader over, nothing to do\n");
3419 return WINED3D_OK;
3422 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3431 if (NULL == ppShader) {
3432 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3433 return WINED3DERR_INVALIDCALL;
3436 *ppShader = This->stateBlock->pixelShader;
3437 if (NULL != *ppShader) {
3438 IWineD3DPixelShader_AddRef(*ppShader);
3440 TRACE("(%p) : returning %p\n", This, *ppShader);
3441 return WINED3D_OK;
3444 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3445 IWineD3DDevice *iface,
3446 UINT start,
3447 CONST BOOL *srcData,
3448 UINT count) {
3450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3451 int i, cnt = min(count, MAX_CONST_B - start);
3453 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3454 iface, srcData, start, count);
3456 if (srcData == NULL || cnt < 0)
3457 return WINED3DERR_INVALIDCALL;
3459 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3460 for (i = 0; i < cnt; i++)
3461 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3463 for (i = start; i < cnt + start; ++i) {
3464 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3465 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3470 return WINED3D_OK;
3473 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3474 IWineD3DDevice *iface,
3475 UINT start,
3476 BOOL *dstData,
3477 UINT count) {
3479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3480 int cnt = min(count, MAX_CONST_B - start);
3482 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3483 iface, dstData, start, count);
3485 if (dstData == NULL || cnt < 0)
3486 return WINED3DERR_INVALIDCALL;
3488 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3489 return WINED3D_OK;
3492 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3493 IWineD3DDevice *iface,
3494 UINT start,
3495 CONST int *srcData,
3496 UINT count) {
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 int i, cnt = min(count, MAX_CONST_I - start);
3501 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3502 iface, srcData, start, count);
3504 if (srcData == NULL || cnt < 0)
3505 return WINED3DERR_INVALIDCALL;
3507 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3508 for (i = 0; i < cnt; i++)
3509 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3510 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3512 for (i = start; i < cnt + start; ++i) {
3513 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3514 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3519 return WINED3D_OK;
3522 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3523 IWineD3DDevice *iface,
3524 UINT start,
3525 int *dstData,
3526 UINT count) {
3528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 int cnt = min(count, MAX_CONST_I - start);
3531 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3532 iface, dstData, start, count);
3534 if (dstData == NULL || cnt < 0)
3535 return WINED3DERR_INVALIDCALL;
3537 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3538 return WINED3D_OK;
3541 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3542 IWineD3DDevice *iface,
3543 UINT start,
3544 CONST float *srcData,
3545 UINT count) {
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 int i;
3550 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3551 iface, srcData, start, count);
3553 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3554 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3555 return WINED3DERR_INVALIDCALL;
3557 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3558 if(TRACE_ON(d3d)) {
3559 for (i = 0; i < count; i++)
3560 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3561 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3564 for (i = start; i < count + start; ++i) {
3565 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3566 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3567 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3568 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3569 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3571 ptr->idx[ptr->count++] = i;
3572 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3574 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3577 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3579 return WINED3D_OK;
3582 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3583 IWineD3DDevice *iface,
3584 UINT start,
3585 float *dstData,
3586 UINT count) {
3588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3589 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3591 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3592 iface, dstData, start, count);
3594 if (dstData == NULL || cnt < 0)
3595 return WINED3DERR_INVALIDCALL;
3597 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3598 return WINED3D_OK;
3601 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3602 static HRESULT
3603 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3604 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3605 unsigned int i;
3606 DWORD DestFVF = dest->fvf;
3607 WINED3DVIEWPORT vp;
3608 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3609 BOOL doClip;
3610 int numTextures;
3612 if (lpStrideData->u.s.normal.lpData) {
3613 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3616 if (lpStrideData->u.s.position.lpData == NULL) {
3617 ERR("Source has no position mask\n");
3618 return WINED3DERR_INVALIDCALL;
3621 /* We might access VBOs from this code, so hold the lock */
3622 ENTER_GL();
3624 if (dest->resource.allocatedMemory == NULL) {
3625 /* This may happen if we do direct locking into a vbo. Unlikely,
3626 * but theoretically possible(ddraw processvertices test)
3628 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3629 if(!dest->resource.allocatedMemory) {
3630 LEAVE_GL();
3631 ERR("Out of memory\n");
3632 return E_OUTOFMEMORY;
3634 if(dest->vbo) {
3635 void *src;
3636 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3637 checkGLcall("glBindBufferARB");
3638 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3639 if(src) {
3640 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3642 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3643 checkGLcall("glUnmapBufferARB");
3647 /* Get a pointer into the destination vbo(create one if none exists) and
3648 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3650 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3651 CreateVBO(dest);
3654 if(dest->vbo) {
3655 unsigned char extrabytes = 0;
3656 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3657 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3658 * this may write 4 extra bytes beyond the area that should be written
3660 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3661 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3662 if(!dest_conv_addr) {
3663 ERR("Out of memory\n");
3664 /* Continue without storing converted vertices */
3666 dest_conv = dest_conv_addr;
3669 /* Should I clip?
3670 * a) WINED3DRS_CLIPPING is enabled
3671 * b) WINED3DVOP_CLIP is passed
3673 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3674 static BOOL warned = FALSE;
3676 * The clipping code is not quite correct. Some things need
3677 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3678 * so disable clipping for now.
3679 * (The graphics in Half-Life are broken, and my processvertices
3680 * test crashes with IDirect3DDevice3)
3681 doClip = TRUE;
3683 doClip = FALSE;
3684 if(!warned) {
3685 warned = TRUE;
3686 FIXME("Clipping is broken and disabled for now\n");
3688 } else doClip = FALSE;
3689 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3691 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3692 WINED3DTS_VIEW,
3693 &view_mat);
3694 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3695 WINED3DTS_PROJECTION,
3696 &proj_mat);
3697 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3698 WINED3DTS_WORLDMATRIX(0),
3699 &world_mat);
3701 TRACE("View mat:\n");
3702 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3703 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3704 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3705 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3707 TRACE("Proj mat:\n");
3708 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3709 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3710 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3711 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3713 TRACE("World mat:\n");
3714 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3715 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3716 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3717 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3719 /* Get the viewport */
3720 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3721 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3722 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3724 multiply_matrix(&mat,&view_mat,&world_mat);
3725 multiply_matrix(&mat,&proj_mat,&mat);
3727 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3729 for (i = 0; i < dwCount; i+= 1) {
3730 unsigned int tex_index;
3732 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3733 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3734 /* The position first */
3735 float *p =
3736 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3737 float x, y, z, rhw;
3738 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3740 /* Multiplication with world, view and projection matrix */
3741 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
3742 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
3743 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
3744 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
3746 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3748 /* WARNING: The following things are taken from d3d7 and were not yet checked
3749 * against d3d8 or d3d9!
3752 /* Clipping conditions: From
3753 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3755 * A vertex is clipped if it does not match the following requirements
3756 * -rhw < x <= rhw
3757 * -rhw < y <= rhw
3758 * 0 < z <= rhw
3759 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3761 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3762 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3766 if( !doClip ||
3767 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3768 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3769 ( rhw > eps ) ) ) {
3771 /* "Normal" viewport transformation (not clipped)
3772 * 1) The values are divided by rhw
3773 * 2) The y axis is negative, so multiply it with -1
3774 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3775 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3776 * 4) Multiply x with Width/2 and add Width/2
3777 * 5) The same for the height
3778 * 6) Add the viewpoint X and Y to the 2D coordinates and
3779 * The minimum Z value to z
3780 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3782 * Well, basically it's simply a linear transformation into viewport
3783 * coordinates
3786 x /= rhw;
3787 y /= rhw;
3788 z /= rhw;
3790 y *= -1;
3792 x *= vp.Width / 2;
3793 y *= vp.Height / 2;
3794 z *= vp.MaxZ - vp.MinZ;
3796 x += vp.Width / 2 + vp.X;
3797 y += vp.Height / 2 + vp.Y;
3798 z += vp.MinZ;
3800 rhw = 1 / rhw;
3801 } else {
3802 /* That vertex got clipped
3803 * Contrary to OpenGL it is not dropped completely, it just
3804 * undergoes a different calculation.
3806 TRACE("Vertex got clipped\n");
3807 x += rhw;
3808 y += rhw;
3810 x /= 2;
3811 y /= 2;
3813 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3814 * outside of the main vertex buffer memory. That needs some more
3815 * investigation...
3819 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3822 ( (float *) dest_ptr)[0] = x;
3823 ( (float *) dest_ptr)[1] = y;
3824 ( (float *) dest_ptr)[2] = z;
3825 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3827 dest_ptr += 3 * sizeof(float);
3829 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3830 dest_ptr += sizeof(float);
3833 if(dest_conv) {
3834 float w = 1 / rhw;
3835 ( (float *) dest_conv)[0] = x * w;
3836 ( (float *) dest_conv)[1] = y * w;
3837 ( (float *) dest_conv)[2] = z * w;
3838 ( (float *) dest_conv)[3] = w;
3840 dest_conv += 3 * sizeof(float);
3842 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3843 dest_conv += sizeof(float);
3847 if (DestFVF & WINED3DFVF_PSIZE) {
3848 dest_ptr += sizeof(DWORD);
3849 if(dest_conv) dest_conv += sizeof(DWORD);
3851 if (DestFVF & WINED3DFVF_NORMAL) {
3852 float *normal =
3853 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3854 /* AFAIK this should go into the lighting information */
3855 FIXME("Didn't expect the destination to have a normal\n");
3856 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3857 if(dest_conv) {
3858 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3862 if (DestFVF & WINED3DFVF_DIFFUSE) {
3863 DWORD *color_d =
3864 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3865 if(!color_d) {
3866 static BOOL warned = FALSE;
3868 if(!warned) {
3869 ERR("No diffuse color in source, but destination has one\n");
3870 warned = TRUE;
3873 *( (DWORD *) dest_ptr) = 0xffffffff;
3874 dest_ptr += sizeof(DWORD);
3876 if(dest_conv) {
3877 *( (DWORD *) dest_conv) = 0xffffffff;
3878 dest_conv += sizeof(DWORD);
3881 else {
3882 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3883 if(dest_conv) {
3884 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3885 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3886 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3887 dest_conv += sizeof(DWORD);
3892 if (DestFVF & WINED3DFVF_SPECULAR) {
3893 /* What's the color value in the feedback buffer? */
3894 DWORD *color_s =
3895 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3896 if(!color_s) {
3897 static BOOL warned = FALSE;
3899 if(!warned) {
3900 ERR("No specular color in source, but destination has one\n");
3901 warned = TRUE;
3904 *( (DWORD *) dest_ptr) = 0xFF000000;
3905 dest_ptr += sizeof(DWORD);
3907 if(dest_conv) {
3908 *( (DWORD *) dest_conv) = 0xFF000000;
3909 dest_conv += sizeof(DWORD);
3912 else {
3913 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3914 if(dest_conv) {
3915 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3916 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3917 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3918 dest_conv += sizeof(DWORD);
3923 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3924 float *tex_coord =
3925 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3926 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3927 if(!tex_coord) {
3928 ERR("No source texture, but destination requests one\n");
3929 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3930 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3932 else {
3933 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3934 if(dest_conv) {
3935 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3941 if(dest_conv) {
3942 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3943 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3944 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3945 dwCount * get_flexible_vertex_size(DestFVF),
3946 dest_conv_addr));
3947 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3948 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3951 LEAVE_GL();
3953 return WINED3D_OK;
3955 #undef copy_and_next
3957 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3959 WineDirect3DVertexStridedData strided;
3960 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3961 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3963 if(pVertexDecl) {
3964 ERR("Output vertex declaration not implemented yet\n");
3967 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3968 * and this call is quite performance critical, so don't call needlessly
3970 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3971 ENTER_GL();
3972 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3973 LEAVE_GL();
3976 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3977 * control the streamIsUP flag, thus restore it afterwards.
3979 This->stateBlock->streamIsUP = FALSE;
3980 memset(&strided, 0, sizeof(strided));
3981 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3982 This->stateBlock->streamIsUP = streamWasUP;
3984 if(vbo || SrcStartIndex) {
3985 unsigned int i;
3986 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3987 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3989 * Also get the start index in, but only loop over all elements if there's something to add at all.
3991 #define FIXSRC(type) \
3992 if(strided.u.s.type.VBO) { \
3993 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3994 strided.u.s.type.VBO = 0; \
3995 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3996 ENTER_GL(); \
3997 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3998 vb->vbo = 0; \
3999 LEAVE_GL(); \
4001 if(strided.u.s.type.lpData) { \
4002 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4004 FIXSRC(position);
4005 FIXSRC(blendWeights);
4006 FIXSRC(blendMatrixIndices);
4007 FIXSRC(normal);
4008 FIXSRC(pSize);
4009 FIXSRC(diffuse);
4010 FIXSRC(specular);
4011 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4012 FIXSRC(texCoords[i]);
4014 FIXSRC(position2);
4015 FIXSRC(normal2);
4016 FIXSRC(tangent);
4017 FIXSRC(binormal);
4018 FIXSRC(tessFactor);
4019 FIXSRC(fog);
4020 FIXSRC(depth);
4021 FIXSRC(sample);
4022 #undef FIXSRC
4025 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4028 /*****
4029 * Get / Set Texture Stage States
4030 * TODO: Verify against dx9 definitions
4031 *****/
4032 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4034 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4036 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4038 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4040 if (Stage >= MAX_TEXTURES) {
4041 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4042 return WINED3D_OK;
4045 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4046 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4047 This->updateStateBlock->textureState[Stage][Type] = Value;
4049 if (This->isRecordingState) {
4050 TRACE("Recording... not performing anything\n");
4051 return WINED3D_OK;
4054 /* Checked after the assignments to allow proper stateblock recording */
4055 if(oldValue == Value) {
4056 TRACE("App is setting the old value over, nothing to do\n");
4057 return WINED3D_OK;
4060 if(Stage > This->stateBlock->lowest_disabled_stage &&
4061 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4062 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4063 * Changes in other states are important on disabled stages too
4065 return WINED3D_OK;
4068 if(Type == WINED3DTSS_COLOROP) {
4069 int i;
4071 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4072 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4073 * they have to be disabled
4075 * The current stage is dirtified below.
4077 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4078 TRACE("Additionally dirtifying stage %d\n", i);
4079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4081 This->stateBlock->lowest_disabled_stage = Stage;
4082 TRACE("New lowest disabled: %d\n", Stage);
4083 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4084 /* Previously disabled stage enabled. Stages above it may need enabling
4085 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4086 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4088 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4091 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4092 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4093 break;
4095 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4098 This->stateBlock->lowest_disabled_stage = i;
4099 TRACE("New lowest disabled: %d\n", i);
4101 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4102 /* TODO: Built a stage -> texture unit mapping for register combiners */
4106 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4108 return WINED3D_OK;
4111 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4113 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4114 *pValue = This->updateStateBlock->textureState[Stage][Type];
4115 return WINED3D_OK;
4118 /*****
4119 * Get / Set Texture
4120 *****/
4121 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4123 IWineD3DBaseTexture *oldTexture;
4125 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4127 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4128 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4131 oldTexture = This->updateStateBlock->textures[Stage];
4133 if(pTexture != NULL) {
4134 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4136 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4137 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4138 return WINED3DERR_INVALIDCALL;
4140 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4143 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4144 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4146 This->updateStateBlock->set.textures[Stage] = TRUE;
4147 This->updateStateBlock->changed.textures[Stage] = TRUE;
4148 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4149 This->updateStateBlock->textures[Stage] = pTexture;
4151 /* Handle recording of state blocks */
4152 if (This->isRecordingState) {
4153 TRACE("Recording... not performing anything\n");
4154 return WINED3D_OK;
4157 if(oldTexture == pTexture) {
4158 TRACE("App is setting the same texture again, nothing to do\n");
4159 return WINED3D_OK;
4162 /** NOTE: MSDN says that setTexture increases the reference count,
4163 * and the the application must set the texture back to null (or have a leaky application),
4164 * This means we should pass the refcount up to the parent
4165 *******************************/
4166 if (NULL != This->updateStateBlock->textures[Stage]) {
4167 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4168 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4170 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4171 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4172 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4173 * so the COLOROP and ALPHAOP have to be dirtified.
4175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4178 if(bindCount == 1) {
4179 new->baseTexture.sampler = Stage;
4181 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4185 if (NULL != oldTexture) {
4186 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4187 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4189 IWineD3DBaseTexture_Release(oldTexture);
4190 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4195 if(bindCount && old->baseTexture.sampler == Stage) {
4196 int i;
4197 /* Have to do a search for the other sampler(s) where the texture is bound to
4198 * Shouldn't happen as long as apps bind a texture only to one stage
4200 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4201 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4202 if(This->updateStateBlock->textures[i] == oldTexture) {
4203 old->baseTexture.sampler = i;
4204 break;
4210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4212 return WINED3D_OK;
4215 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4218 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4220 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4221 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4224 *ppTexture=This->stateBlock->textures[Stage];
4225 if (*ppTexture)
4226 IWineD3DBaseTexture_AddRef(*ppTexture);
4228 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4230 return WINED3D_OK;
4233 /*****
4234 * Get Back Buffer
4235 *****/
4236 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4237 IWineD3DSurface **ppBackBuffer) {
4238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4239 IWineD3DSwapChain *swapChain;
4240 HRESULT hr;
4242 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4244 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4245 if (hr == WINED3D_OK) {
4246 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4247 IWineD3DSwapChain_Release(swapChain);
4248 } else {
4249 *ppBackBuffer = NULL;
4251 return hr;
4254 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4256 WARN("(%p) : stub, calling idirect3d for now\n", This);
4257 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4260 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 IWineD3DSwapChain *swapChain;
4263 HRESULT hr;
4265 if(iSwapChain > 0) {
4266 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4267 if (hr == WINED3D_OK) {
4268 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4269 IWineD3DSwapChain_Release(swapChain);
4270 } else {
4271 FIXME("(%p) Error getting display mode\n", This);
4273 } else {
4274 /* Don't read the real display mode,
4275 but return the stored mode instead. X11 can't change the color
4276 depth, and some apps are pretty angry if they SetDisplayMode from
4277 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4279 Also don't relay to the swapchain because with ddraw it's possible
4280 that there isn't a swapchain at all */
4281 pMode->Width = This->ddraw_width;
4282 pMode->Height = This->ddraw_height;
4283 pMode->Format = This->ddraw_format;
4284 pMode->RefreshRate = 0;
4285 hr = WINED3D_OK;
4288 return hr;
4291 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4293 TRACE("(%p)->(%p)\n", This, hWnd);
4295 if(This->ddraw_fullscreen) {
4296 if(This->ddraw_window && This->ddraw_window != hWnd) {
4297 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4299 if(hWnd && This->ddraw_window != hWnd) {
4300 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4304 This->ddraw_window = hWnd;
4305 return WINED3D_OK;
4308 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4310 TRACE("(%p)->(%p)\n", This, hWnd);
4312 *hWnd = This->ddraw_window;
4313 return WINED3D_OK;
4316 /*****
4317 * Stateblock related functions
4318 *****/
4320 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4322 IWineD3DStateBlockImpl *object;
4323 HRESULT temp_result;
4324 int i;
4326 TRACE("(%p)\n", This);
4328 if (This->isRecordingState) {
4329 return WINED3DERR_INVALIDCALL;
4332 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4333 if (NULL == object ) {
4334 FIXME("(%p)Error allocating memory for stateblock\n", This);
4335 return E_OUTOFMEMORY;
4337 TRACE("(%p) created object %p\n", This, object);
4338 object->wineD3DDevice= This;
4339 /** FIXME: object->parent = parent; **/
4340 object->parent = NULL;
4341 object->blockType = WINED3DSBT_ALL;
4342 object->ref = 1;
4343 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4345 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4346 list_init(&object->lightMap[i]);
4349 temp_result = allocate_shader_constants(object);
4350 if (WINED3D_OK != temp_result)
4351 return temp_result;
4353 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4354 This->updateStateBlock = object;
4355 This->isRecordingState = TRUE;
4357 TRACE("(%p) recording stateblock %p\n",This , object);
4358 return WINED3D_OK;
4361 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4364 if (!This->isRecordingState) {
4365 FIXME("(%p) not recording! returning error\n", This);
4366 *ppStateBlock = NULL;
4367 return WINED3DERR_INVALIDCALL;
4370 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4371 This->isRecordingState = FALSE;
4372 This->updateStateBlock = This->stateBlock;
4373 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4374 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4375 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4376 return WINED3D_OK;
4379 /*****
4380 * Scene related functions
4381 *****/
4382 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4383 /* At the moment we have no need for any functionality at the beginning
4384 of a scene */
4385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4386 TRACE("(%p)\n", This);
4388 if(This->inScene) {
4389 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4390 return WINED3DERR_INVALIDCALL;
4392 This->inScene = TRUE;
4393 return WINED3D_OK;
4396 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4398 TRACE("(%p)\n", This);
4400 if(!This->inScene) {
4401 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4402 return WINED3DERR_INVALIDCALL;
4405 ENTER_GL();
4406 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4407 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4409 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4410 glFlush();
4411 checkGLcall("glFlush");
4412 LEAVE_GL();
4414 This->inScene = FALSE;
4415 return WINED3D_OK;
4418 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4419 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4420 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4422 IWineD3DSwapChain *swapChain = NULL;
4423 int i;
4424 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4426 TRACE("(%p) Presenting the frame\n", This);
4428 for(i = 0 ; i < swapchains ; i ++) {
4430 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4431 TRACE("presentinng chain %d, %p\n", i, swapChain);
4432 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4433 IWineD3DSwapChain_Release(swapChain);
4436 return WINED3D_OK;
4439 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4440 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4444 GLbitfield glMask = 0;
4445 unsigned int i;
4446 CONST WINED3DRECT* curRect;
4448 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4449 Count, pRects, Flags, Color, Z, Stencil);
4451 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4452 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4453 /* TODO: What about depth stencil buffers without stencil bits? */
4454 return WINED3DERR_INVALIDCALL;
4457 ENTER_GL();
4458 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4459 * and not the last active one.
4462 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4463 apply_fbo_state(iface);
4466 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4468 if (Count > 0 && pRects) {
4469 curRect = pRects;
4470 } else {
4471 curRect = NULL;
4474 /* Only set the values up once, as they are not changing */
4475 if (Flags & WINED3DCLEAR_STENCIL) {
4476 glClearStencil(Stencil);
4477 checkGLcall("glClearStencil");
4478 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4479 glStencilMask(0xFFFFFFFF);
4482 if (Flags & WINED3DCLEAR_ZBUFFER) {
4483 glDepthMask(GL_TRUE);
4484 glClearDepth(Z);
4485 checkGLcall("glClearDepth");
4486 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4490 if (Flags & WINED3DCLEAR_TARGET) {
4491 TRACE("Clearing screen with glClear to color %x\n", Color);
4492 glClearColor(D3DCOLOR_R(Color),
4493 D3DCOLOR_G(Color),
4494 D3DCOLOR_B(Color),
4495 D3DCOLOR_A(Color));
4496 checkGLcall("glClearColor");
4498 /* Clear ALL colors! */
4499 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4500 glMask = glMask | GL_COLOR_BUFFER_BIT;
4503 if (!curRect) {
4504 /* In drawable flag is set below */
4506 if (This->render_offscreen) {
4507 glScissor(This->stateBlock->viewport.X,
4508 This->stateBlock->viewport.Y,
4509 This->stateBlock->viewport.Width,
4510 This->stateBlock->viewport.Height);
4511 } else {
4512 glScissor(This->stateBlock->viewport.X,
4513 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4514 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4515 This->stateBlock->viewport.Width,
4516 This->stateBlock->viewport.Height);
4518 checkGLcall("glScissor");
4519 glClear(glMask);
4520 checkGLcall("glClear");
4521 } else {
4522 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4523 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4525 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4526 curRect[0].x2 < target->currentDesc.Width ||
4527 curRect[0].y2 < target->currentDesc.Height) {
4528 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4529 blt_to_drawable(This, target);
4533 /* Now process each rect in turn */
4534 for (i = 0; i < Count; i++) {
4535 /* Note gl uses lower left, width/height */
4536 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4537 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4538 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4539 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4541 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4542 * The rectangle is not cleared, no error is returned, but further rectanlges are
4543 * still cleared if they are valid
4545 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4546 TRACE("Rectangle with negative dimensions, ignoring\n");
4547 continue;
4550 if(This->render_offscreen) {
4551 glScissor(curRect[i].x1, curRect[i].y1,
4552 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4553 } else {
4554 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4555 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4557 checkGLcall("glScissor");
4559 glClear(glMask);
4560 checkGLcall("glClear");
4564 /* Restore the old values (why..?) */
4565 if (Flags & WINED3DCLEAR_STENCIL) {
4566 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4568 if (Flags & WINED3DCLEAR_TARGET) {
4569 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4570 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4571 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4572 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4573 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4576 LEAVE_GL();
4578 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4579 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4581 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4582 target->Flags |= SFLAG_INTEXTURE;
4583 target->Flags &= ~SFLAG_INSYSMEM;
4584 } else {
4585 target->Flags |= SFLAG_INDRAWABLE;
4586 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4588 return WINED3D_OK;
4591 /*****
4592 * Drawing functions
4593 *****/
4594 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4595 UINT PrimitiveCount) {
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4599 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4600 debug_d3dprimitivetype(PrimitiveType),
4601 StartVertex, PrimitiveCount);
4603 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4604 if(This->stateBlock->streamIsUP) {
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4606 This->stateBlock->streamIsUP = FALSE;
4609 if(This->stateBlock->loadBaseVertexIndex != 0) {
4610 This->stateBlock->loadBaseVertexIndex = 0;
4611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4613 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4614 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4615 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4616 return WINED3D_OK;
4619 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4620 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4621 WINED3DPRIMITIVETYPE PrimitiveType,
4622 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 UINT idxStride = 2;
4626 IWineD3DIndexBuffer *pIB;
4627 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4628 GLuint vbo;
4630 pIB = This->stateBlock->pIndexData;
4631 if (!pIB) {
4632 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4633 * without an index buffer set. (The first time at least...)
4634 * D3D8 simply dies, but I doubt it can do much harm to return
4635 * D3DERR_INVALIDCALL there as well. */
4636 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4637 return WINED3DERR_INVALIDCALL;
4640 if(This->stateBlock->streamIsUP) {
4641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4642 This->stateBlock->streamIsUP = FALSE;
4644 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4646 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4647 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4648 minIndex, NumVertices, startIndex, primCount);
4650 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4651 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4652 idxStride = 2;
4653 } else {
4654 idxStride = 4;
4657 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4658 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4662 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4663 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4665 return WINED3D_OK;
4668 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4669 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4670 UINT VertexStreamZeroStride) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4674 debug_d3dprimitivetype(PrimitiveType),
4675 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4677 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4678 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4679 This->stateBlock->streamOffset[0] = 0;
4680 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4681 This->stateBlock->streamIsUP = TRUE;
4682 This->stateBlock->loadBaseVertexIndex = 0;
4684 /* TODO: Only mark dirty if drawing from a different UP address */
4685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4687 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4688 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4690 /* MSDN specifies stream zero settings must be set to NULL */
4691 This->stateBlock->streamStride[0] = 0;
4692 This->stateBlock->streamSource[0] = NULL;
4694 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4695 * the new stream sources or use UP drawing again
4697 return WINED3D_OK;
4700 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4701 UINT MinVertexIndex, UINT NumVertices,
4702 UINT PrimitiveCount, CONST void* pIndexData,
4703 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4704 UINT VertexStreamZeroStride) {
4705 int idxStride;
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4709 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4710 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4711 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4713 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4714 idxStride = 2;
4715 } else {
4716 idxStride = 4;
4719 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4720 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4721 This->stateBlock->streamIsUP = TRUE;
4722 This->stateBlock->streamOffset[0] = 0;
4723 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4725 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4726 This->stateBlock->baseVertexIndex = 0;
4727 This->stateBlock->loadBaseVertexIndex = 0;
4728 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4732 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4734 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4735 This->stateBlock->streamSource[0] = NULL;
4736 This->stateBlock->streamStride[0] = 0;
4737 This->stateBlock->pIndexData = NULL;
4738 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4739 * SetStreamSource to specify a vertex buffer
4742 return WINED3D_OK;
4745 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4748 /* Mark the state dirty until we have nicer tracking
4749 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4750 * that value.
4752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4754 This->stateBlock->baseVertexIndex = 0;
4755 This->up_strided = DrawPrimStrideData;
4756 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4757 This->up_strided = NULL;
4758 return WINED3D_OK;
4760 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4761 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4763 HRESULT hr = WINED3D_OK;
4764 WINED3DRESOURCETYPE sourceType;
4765 WINED3DRESOURCETYPE destinationType;
4766 int i ,levels;
4768 /* TODO: think about moving the code into IWineD3DBaseTexture */
4770 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4772 /* verify that the source and destination textures aren't NULL */
4773 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4774 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4775 This, pSourceTexture, pDestinationTexture);
4776 hr = WINED3DERR_INVALIDCALL;
4779 if (pSourceTexture == pDestinationTexture) {
4780 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4781 This, pSourceTexture, pDestinationTexture);
4782 hr = WINED3DERR_INVALIDCALL;
4784 /* Verify that the source and destination textures are the same type */
4785 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4786 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4788 if (sourceType != destinationType) {
4789 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4790 This);
4791 hr = WINED3DERR_INVALIDCALL;
4794 /* check that both textures have the identical numbers of levels */
4795 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4796 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4797 hr = WINED3DERR_INVALIDCALL;
4800 if (WINED3D_OK == hr) {
4802 /* Make sure that the destination texture is loaded */
4803 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4805 /* Update every surface level of the texture */
4806 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4808 switch (sourceType) {
4809 case WINED3DRTYPE_TEXTURE:
4811 IWineD3DSurface *srcSurface;
4812 IWineD3DSurface *destSurface;
4814 for (i = 0 ; i < levels ; ++i) {
4815 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4816 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4817 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4818 IWineD3DSurface_Release(srcSurface);
4819 IWineD3DSurface_Release(destSurface);
4820 if (WINED3D_OK != hr) {
4821 WARN("(%p) : Call to update surface failed\n", This);
4822 return hr;
4826 break;
4827 case WINED3DRTYPE_CUBETEXTURE:
4829 IWineD3DSurface *srcSurface;
4830 IWineD3DSurface *destSurface;
4831 WINED3DCUBEMAP_FACES faceType;
4833 for (i = 0 ; i < levels ; ++i) {
4834 /* Update each cube face */
4835 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4836 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4837 if (WINED3D_OK != hr) {
4838 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4839 } else {
4840 TRACE("Got srcSurface %p\n", srcSurface);
4842 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4843 if (WINED3D_OK != hr) {
4844 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4845 } else {
4846 TRACE("Got desrSurface %p\n", destSurface);
4848 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4849 IWineD3DSurface_Release(srcSurface);
4850 IWineD3DSurface_Release(destSurface);
4851 if (WINED3D_OK != hr) {
4852 WARN("(%p) : Call to update surface failed\n", This);
4853 return hr;
4858 break;
4859 #if 0 /* TODO: Add support for volume textures */
4860 case WINED3DRTYPE_VOLUMETEXTURE:
4862 IWineD3DVolume srcVolume = NULL;
4863 IWineD3DSurface destVolume = NULL;
4865 for (i = 0 ; i < levels ; ++i) {
4866 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4867 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4868 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4869 IWineD3DVolume_Release(srcSurface);
4870 IWineD3DVolume_Release(destSurface);
4871 if (WINED3D_OK != hr) {
4872 WARN("(%p) : Call to update volume failed\n", This);
4873 return hr;
4877 break;
4878 #endif
4879 default:
4880 FIXME("(%p) : Unsupported source and destination type\n", This);
4881 hr = WINED3DERR_INVALIDCALL;
4885 return hr;
4888 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4889 IWineD3DSwapChain *swapChain;
4890 HRESULT hr;
4891 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4892 if(hr == WINED3D_OK) {
4893 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4894 IWineD3DSwapChain_Release(swapChain);
4896 return hr;
4899 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 /* return a sensible default */
4902 *pNumPasses = 1;
4903 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4904 FIXME("(%p) : stub\n", This);
4905 return WINED3D_OK;
4908 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4910 int j;
4911 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4912 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4913 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4914 return WINED3DERR_INVALIDCALL;
4916 for (j = 0; j < 256; ++j) {
4917 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4918 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4919 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4920 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4922 TRACE("(%p) : returning\n", This);
4923 return WINED3D_OK;
4926 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4928 int j;
4929 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4930 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4931 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4932 return WINED3DERR_INVALIDCALL;
4934 for (j = 0; j < 256; ++j) {
4935 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4936 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4937 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4938 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4940 TRACE("(%p) : returning\n", This);
4941 return WINED3D_OK;
4944 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4946 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4947 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4948 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4949 return WINED3DERR_INVALIDCALL;
4951 /*TODO: stateblocks */
4952 This->currentPalette = PaletteNumber;
4953 TRACE("(%p) : returning\n", This);
4954 return WINED3D_OK;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4959 if (PaletteNumber == NULL) {
4960 WARN("(%p) : returning Invalid Call\n", This);
4961 return WINED3DERR_INVALIDCALL;
4963 /*TODO: stateblocks */
4964 *PaletteNumber = This->currentPalette;
4965 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4966 return WINED3D_OK;
4969 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4971 static BOOL showFixmes = TRUE;
4972 if (showFixmes) {
4973 FIXME("(%p) : stub\n", This);
4974 showFixmes = FALSE;
4977 This->softwareVertexProcessing = bSoftware;
4978 return WINED3D_OK;
4982 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4984 static BOOL showFixmes = TRUE;
4985 if (showFixmes) {
4986 FIXME("(%p) : stub\n", This);
4987 showFixmes = FALSE;
4989 return This->softwareVertexProcessing;
4993 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4995 IWineD3DSwapChain *swapChain;
4996 HRESULT hr;
4998 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5000 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5001 if(hr == WINED3D_OK){
5002 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5003 IWineD3DSwapChain_Release(swapChain);
5004 }else{
5005 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5007 return hr;
5011 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5013 static BOOL showfixmes = TRUE;
5014 if(nSegments != 0.0f) {
5015 if( showfixmes) {
5016 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5017 showfixmes = FALSE;
5020 return WINED3D_OK;
5023 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5025 static BOOL showfixmes = TRUE;
5026 if( showfixmes) {
5027 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5028 showfixmes = FALSE;
5030 return 0.0f;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5035 /** TODO: remove casts to IWineD3DSurfaceImpl
5036 * NOTE: move code to surface to accomplish this
5037 ****************************************/
5038 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5039 int srcWidth, srcHeight;
5040 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5041 WINED3DFORMAT destFormat, srcFormat;
5042 UINT destSize;
5043 int srcLeft, destLeft, destTop;
5044 WINED3DPOOL srcPool, destPool;
5045 int offset = 0;
5046 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5047 glDescriptor *glDescription = NULL;
5049 WINED3DSURFACE_DESC winedesc;
5051 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5052 memset(&winedesc, 0, sizeof(winedesc));
5053 winedesc.Width = &srcSurfaceWidth;
5054 winedesc.Height = &srcSurfaceHeight;
5055 winedesc.Pool = &srcPool;
5056 winedesc.Format = &srcFormat;
5058 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5060 winedesc.Width = &destSurfaceWidth;
5061 winedesc.Height = &destSurfaceHeight;
5062 winedesc.Pool = &destPool;
5063 winedesc.Format = &destFormat;
5064 winedesc.Size = &destSize;
5066 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5068 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5069 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5070 return WINED3DERR_INVALIDCALL;
5073 if (destFormat == WINED3DFMT_UNKNOWN) {
5074 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5075 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5077 /* Get the update surface description */
5078 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5081 ENTER_GL();
5083 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5085 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5086 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5087 checkGLcall("glActiveTextureARB");
5090 /* Make sure the surface is loaded and up to date */
5091 IWineD3DSurface_PreLoad(pDestinationSurface);
5093 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5095 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5096 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5097 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5098 srcLeft = pSourceRect ? pSourceRect->left : 0;
5099 destLeft = pDestPoint ? pDestPoint->x : 0;
5100 destTop = pDestPoint ? pDestPoint->y : 0;
5103 /* This function doesn't support compressed textures
5104 the pitch is just bytesPerPixel * width */
5105 if(srcWidth != srcSurfaceWidth || srcLeft ){
5106 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5107 offset += srcLeft * pSrcSurface->bytesPerPixel;
5108 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5110 /* TODO DXT formats */
5112 if(pSourceRect != NULL && pSourceRect->top != 0){
5113 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5115 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5116 ,This
5117 ,glDescription->level
5118 ,destLeft
5119 ,destTop
5120 ,srcWidth
5121 ,srcHeight
5122 ,glDescription->glFormat
5123 ,glDescription->glType
5124 ,IWineD3DSurface_GetData(pSourceSurface)
5127 /* Sanity check */
5128 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5130 /* need to lock the surface to get the data */
5131 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5134 /* TODO: Cube and volume support */
5135 if(rowoffset != 0){
5136 /* not a whole row so we have to do it a line at a time */
5137 int j;
5139 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5140 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5142 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5144 glTexSubImage2D(glDescription->target
5145 ,glDescription->level
5146 ,destLeft
5148 ,srcWidth
5150 ,glDescription->glFormat
5151 ,glDescription->glType
5152 ,data /* could be quicker using */
5154 data += rowoffset;
5157 } else { /* Full width, so just write out the whole texture */
5159 if (WINED3DFMT_DXT1 == destFormat ||
5160 WINED3DFMT_DXT2 == destFormat ||
5161 WINED3DFMT_DXT3 == destFormat ||
5162 WINED3DFMT_DXT4 == destFormat ||
5163 WINED3DFMT_DXT5 == destFormat) {
5164 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5165 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5166 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5167 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5168 } if (destFormat != srcFormat) {
5169 FIXME("Updating mixed format compressed texture is not curretly support\n");
5170 } else {
5171 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5172 glDescription->level,
5173 glDescription->glFormatInternal,
5174 srcWidth,
5175 srcHeight,
5177 destSize,
5178 IWineD3DSurface_GetData(pSourceSurface));
5180 } else {
5181 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5185 } else {
5186 glTexSubImage2D(glDescription->target
5187 ,glDescription->level
5188 ,destLeft
5189 ,destTop
5190 ,srcWidth
5191 ,srcHeight
5192 ,glDescription->glFormat
5193 ,glDescription->glType
5194 ,IWineD3DSurface_GetData(pSourceSurface)
5198 checkGLcall("glTexSubImage2D");
5200 LEAVE_GL();
5202 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5203 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5206 return WINED3D_OK;
5209 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5211 struct WineD3DRectPatch *patch;
5212 unsigned int i;
5213 struct list *e;
5214 BOOL found;
5215 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5217 if(!(Handle || pRectPatchInfo)) {
5218 /* TODO: Write a test for the return value, thus the FIXME */
5219 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5220 return WINED3DERR_INVALIDCALL;
5223 if(Handle) {
5224 i = PATCHMAP_HASHFUNC(Handle);
5225 found = FALSE;
5226 LIST_FOR_EACH(e, &This->patches[i]) {
5227 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5228 if(patch->Handle == Handle) {
5229 found = TRUE;
5230 break;
5234 if(!found) {
5235 TRACE("Patch does not exist. Creating a new one\n");
5236 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5237 patch->Handle = Handle;
5238 list_add_head(&This->patches[i], &patch->entry);
5239 } else {
5240 TRACE("Found existing patch %p\n", patch);
5242 } else {
5243 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5244 * attributes we have to tesselate, read back, and draw. This needs a patch
5245 * management structure instance. Create one.
5247 * A possible improvement is to check if a vertex shader is used, and if not directly
5248 * draw the patch.
5250 FIXME("Drawing an uncached patch. This is slow\n");
5251 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5254 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5255 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5256 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5257 HRESULT hr;
5258 TRACE("Tesselation density or patch info changed, retesselating\n");
5260 if(pRectPatchInfo) {
5261 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5263 patch->numSegs[0] = pNumSegs[0];
5264 patch->numSegs[1] = pNumSegs[1];
5265 patch->numSegs[2] = pNumSegs[2];
5266 patch->numSegs[3] = pNumSegs[3];
5268 hr = tesselate_rectpatch(This, patch);
5269 if(FAILED(hr)) {
5270 WARN("Patch tesselation failed\n");
5272 /* Do not release the handle to store the params of the patch */
5273 if(!Handle) {
5274 HeapFree(GetProcessHeap(), 0, patch);
5276 return hr;
5280 This->currentPatch = patch;
5281 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5282 This->currentPatch = NULL;
5284 /* Destroy uncached patches */
5285 if(!Handle) {
5286 HeapFree(GetProcessHeap(), 0, patch->mem);
5287 HeapFree(GetProcessHeap(), 0, patch);
5289 return WINED3D_OK;
5292 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5293 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5295 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5296 FIXME("(%p) : Stub\n", This);
5297 return WINED3D_OK;
5300 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 int i;
5303 struct WineD3DRectPatch *patch;
5304 struct list *e;
5305 TRACE("(%p) Handle(%d)\n", This, Handle);
5307 i = PATCHMAP_HASHFUNC(Handle);
5308 LIST_FOR_EACH(e, &This->patches[i]) {
5309 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5310 if(patch->Handle == Handle) {
5311 TRACE("Deleting patch %p\n", patch);
5312 list_remove(&patch->entry);
5313 HeapFree(GetProcessHeap(), 0, patch->mem);
5314 HeapFree(GetProcessHeap(), 0, patch);
5315 return WINED3D_OK;
5319 /* TODO: Write a test for the return value */
5320 FIXME("Attempt to destroy nonexistant patch\n");
5321 return WINED3DERR_INVALIDCALL;
5324 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5325 HRESULT hr;
5326 IWineD3DSwapChain *swapchain;
5328 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5329 if (SUCCEEDED(hr)) {
5330 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5331 return swapchain;
5334 return NULL;
5337 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 if (!*fbo) {
5341 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5342 checkGLcall("glGenFramebuffersEXT()");
5344 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5345 checkGLcall("glBindFramebuffer()");
5348 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5349 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5350 IWineD3DBaseTextureImpl *texture_impl;
5351 GLenum texttarget, target;
5352 GLint old_binding;
5354 texttarget = surface_impl->glDescription.target;
5355 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5356 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5358 IWineD3DSurface_PreLoad(surface);
5360 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5361 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5362 glBindTexture(target, old_binding);
5364 /* Update base texture states array */
5365 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5366 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5367 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5368 if (texture_impl->baseTexture.bindCount) {
5369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5372 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5375 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5377 checkGLcall("attach_surface_fbo");
5380 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5382 IWineD3DSwapChain *swapchain;
5384 swapchain = get_swapchain(surface);
5385 if (swapchain) {
5386 GLenum buffer;
5388 TRACE("Surface %p is onscreen\n", surface);
5390 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5391 buffer = surface_get_gl_buffer(surface, swapchain);
5392 glDrawBuffer(buffer);
5393 checkGLcall("glDrawBuffer()");
5394 } else {
5395 TRACE("Surface %p is offscreen\n", surface);
5396 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5397 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5400 if (rect) {
5401 glEnable(GL_SCISSOR_TEST);
5402 if(!swapchain) {
5403 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5404 } else {
5405 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5406 rect->x2 - rect->x1, rect->y2 - rect->y1);
5408 checkGLcall("glScissor");
5409 } else {
5410 glDisable(GL_SCISSOR_TEST);
5412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5414 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5417 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5418 glClear(GL_COLOR_BUFFER_BIT);
5419 checkGLcall("glClear");
5421 if (This->render_offscreen) {
5422 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5423 } else {
5424 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5425 checkGLcall("glBindFramebuffer()");
5428 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5429 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5430 glDrawBuffer(GL_BACK);
5431 checkGLcall("glDrawBuffer()");
5435 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5437 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5438 WINEDDBLTFX BltFx;
5439 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5441 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5442 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5443 return WINED3DERR_INVALIDCALL;
5446 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5447 color_fill_fbo(iface, pSurface, pRect, color);
5448 return WINED3D_OK;
5449 } else {
5450 /* Just forward this to the DirectDraw blitting engine */
5451 memset(&BltFx, 0, sizeof(BltFx));
5452 BltFx.dwSize = sizeof(BltFx);
5453 BltFx.u5.dwFillColor = color;
5454 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5458 /* rendertarget and deptth stencil functions */
5459 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5462 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5463 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5464 return WINED3DERR_INVALIDCALL;
5467 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5468 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5469 /* Note inc ref on returned surface */
5470 if(*ppRenderTarget != NULL)
5471 IWineD3DSurface_AddRef(*ppRenderTarget);
5472 return WINED3D_OK;
5475 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5477 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5478 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5479 IWineD3DSwapChainImpl *Swapchain;
5480 HRESULT hr;
5482 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5484 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5485 if(hr != WINED3D_OK) {
5486 ERR("Can't get the swapchain\n");
5487 return hr;
5490 /* Make sure to release the swapchain */
5491 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5493 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5494 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5495 return WINED3DERR_INVALIDCALL;
5497 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5498 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5499 return WINED3DERR_INVALIDCALL;
5502 if(Swapchain->frontBuffer != Front) {
5503 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5505 if(Swapchain->frontBuffer)
5506 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5507 Swapchain->frontBuffer = Front;
5509 if(Swapchain->frontBuffer) {
5510 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5514 if(Back && !Swapchain->backBuffer) {
5515 /* We need memory for the back buffer array - only one back buffer this way */
5516 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5517 if(!Swapchain->backBuffer) {
5518 ERR("Out of memory\n");
5519 return E_OUTOFMEMORY;
5523 if(Swapchain->backBuffer[0] != Back) {
5524 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5526 /* What to do about the context here in the case of multithreading? Not sure.
5527 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5529 ENTER_GL();
5530 if(!Swapchain->backBuffer[0]) {
5531 /* GL was told to draw to the front buffer at creation,
5532 * undo that
5534 glDrawBuffer(GL_BACK);
5535 checkGLcall("glDrawBuffer(GL_BACK)");
5536 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5537 Swapchain->presentParms.BackBufferCount = 1;
5538 } else if (!Back) {
5539 /* That makes problems - disable for now */
5540 /* glDrawBuffer(GL_FRONT); */
5541 checkGLcall("glDrawBuffer(GL_FRONT)");
5542 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5543 Swapchain->presentParms.BackBufferCount = 0;
5545 LEAVE_GL();
5547 if(Swapchain->backBuffer[0])
5548 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5549 Swapchain->backBuffer[0] = Back;
5551 if(Swapchain->backBuffer[0]) {
5552 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5553 } else {
5554 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5559 return WINED3D_OK;
5562 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5564 *ppZStencilSurface = This->depthStencilBuffer;
5565 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5567 if(*ppZStencilSurface != NULL) {
5568 /* Note inc ref on returned surface */
5569 IWineD3DSurface_AddRef(*ppZStencilSurface);
5571 return WINED3D_OK;
5574 /* TODO: Handle stencil attachments */
5575 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5579 TRACE("Set depth stencil to %p\n", depth_stencil);
5581 if (depth_stencil_impl) {
5582 if (depth_stencil_impl->current_renderbuffer) {
5583 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5584 checkGLcall("glFramebufferRenderbufferEXT()");
5585 } else {
5586 IWineD3DBaseTextureImpl *texture_impl;
5587 GLenum texttarget, target;
5588 GLint old_binding = 0;
5590 texttarget = depth_stencil_impl->glDescription.target;
5591 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5592 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5594 IWineD3DSurface_PreLoad(depth_stencil);
5596 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5597 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5598 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5599 glBindTexture(target, old_binding);
5601 /* Update base texture states array */
5602 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5603 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5604 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5605 if (texture_impl->baseTexture.bindCount) {
5606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5609 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5612 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5613 checkGLcall("glFramebufferTexture2DEXT()");
5615 } else {
5616 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5617 checkGLcall("glFramebufferTexture2DEXT()");
5621 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5623 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5625 TRACE("Set render target %u to %p\n", idx, render_target);
5627 if (rtimpl) {
5628 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5629 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5630 } else {
5631 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5632 checkGLcall("glFramebufferTexture2DEXT()");
5634 This->draw_buffers[idx] = GL_NONE;
5638 static void check_fbo_status(IWineD3DDevice *iface) {
5639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5640 GLenum status;
5642 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5643 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5644 TRACE("FBO complete\n");
5645 } else {
5646 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5648 /* Dump the FBO attachments */
5649 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5650 IWineD3DSurfaceImpl *attachment;
5651 int i;
5653 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5654 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5655 if (attachment) {
5656 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5657 attachment->pow2Width, attachment->pow2Height);
5660 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5661 if (attachment) {
5662 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5663 attachment->pow2Width, attachment->pow2Height);
5669 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5671 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5672 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5674 if (!ds_impl) return FALSE;
5676 if (ds_impl->current_renderbuffer) {
5677 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5678 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5681 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5682 rt_impl->pow2Height != ds_impl->pow2Height);
5685 void apply_fbo_state(IWineD3DDevice *iface) {
5686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5687 unsigned int i;
5689 if (This->render_offscreen) {
5690 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5692 /* Apply render targets */
5693 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5694 IWineD3DSurface *render_target = This->render_targets[i];
5695 if (This->fbo_color_attachments[i] != render_target) {
5696 set_render_target_fbo(iface, i, render_target);
5697 This->fbo_color_attachments[i] = render_target;
5701 /* Apply depth targets */
5702 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5703 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5704 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5706 if (This->stencilBufferTarget) {
5707 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5709 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5710 This->fbo_depth_attachment = This->stencilBufferTarget;
5713 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5714 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5715 checkGLcall("glDrawBuffers()");
5716 } else {
5717 glDrawBuffer(This->draw_buffers[0]);
5718 checkGLcall("glDrawBuffer()");
5720 } else {
5721 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5724 check_fbo_status(iface);
5727 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5728 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5731 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5732 GLenum gl_filter;
5734 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5735 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5736 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5737 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5739 switch (filter) {
5740 case WINED3DTEXF_LINEAR:
5741 gl_filter = GL_LINEAR;
5742 break;
5744 default:
5745 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5746 case WINED3DTEXF_NONE:
5747 case WINED3DTEXF_POINT:
5748 gl_filter = GL_NEAREST;
5749 break;
5752 /* Attach src surface to src fbo */
5753 src_swapchain = get_swapchain(src_surface);
5754 ENTER_GL();
5755 if (src_swapchain) {
5756 GLenum buffer;
5758 TRACE("Source surface %p is onscreen\n", src_surface);
5759 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5761 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5762 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5763 glReadBuffer(buffer);
5764 checkGLcall("glReadBuffer()");
5766 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5767 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5768 } else {
5769 TRACE("Source surface %p is offscreen\n", src_surface);
5770 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5771 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5772 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5773 checkGLcall("glReadBuffer()");
5776 /* Attach dst surface to dst fbo */
5777 dst_swapchain = get_swapchain(dst_surface);
5778 if (dst_swapchain) {
5779 GLenum buffer;
5781 TRACE("Destination surface %p is onscreen\n", dst_surface);
5782 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5784 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5785 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5786 glDrawBuffer(buffer);
5787 checkGLcall("glDrawBuffer()");
5789 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5790 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5791 } else {
5792 TRACE("Destination surface %p is offscreen\n", dst_surface);
5794 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5795 if(!src_swapchain) {
5796 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5799 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5800 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5801 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5802 checkGLcall("glDrawBuffer()");
5804 glDisable(GL_SCISSOR_TEST);
5805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5807 if (flip) {
5808 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5809 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5810 checkGLcall("glBlitFramebuffer()");
5811 } else {
5812 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5813 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5814 checkGLcall("glBlitFramebuffer()");
5817 if (This->render_offscreen) {
5818 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5819 } else {
5820 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5821 checkGLcall("glBindFramebuffer()");
5824 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5825 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5826 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5827 glDrawBuffer(GL_BACK);
5828 checkGLcall("glDrawBuffer()");
5830 LEAVE_GL();
5833 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 WINED3DVIEWPORT viewport;
5837 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5839 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5840 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5841 return WINED3DERR_INVALIDCALL;
5844 /* MSDN says that null disables the render target
5845 but a device must always be associated with a render target
5846 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5848 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5849 for more details
5851 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5852 FIXME("Trying to set render target 0 to NULL\n");
5853 return WINED3DERR_INVALIDCALL;
5855 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5856 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5857 return WINED3DERR_INVALIDCALL;
5860 /* If we are trying to set what we already have, don't bother */
5861 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5862 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5863 return WINED3D_OK;
5865 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5866 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5867 This->render_targets[RenderTargetIndex] = pRenderTarget;
5869 /* Render target 0 is special */
5870 if(RenderTargetIndex == 0) {
5871 /* Finally, reset the viewport as the MSDN states. */
5872 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5873 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5874 viewport.X = 0;
5875 viewport.Y = 0;
5876 viewport.MaxZ = 1.0f;
5877 viewport.MinZ = 0.0f;
5878 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5879 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5880 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5884 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5885 * ctx properly.
5886 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5887 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5889 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5891 return WINED3D_OK;
5894 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 HRESULT hr = WINED3D_OK;
5897 IWineD3DSurface *tmp;
5899 TRACE("(%p) Swapping z-buffer\n",This);
5901 if (pNewZStencil == This->stencilBufferTarget) {
5902 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5903 } else {
5904 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5905 * depending on the renter target implementation being used.
5906 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5907 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5908 * stencil buffer and incure an extra memory overhead
5909 ******************************************************/
5911 tmp = This->stencilBufferTarget;
5912 This->stencilBufferTarget = pNewZStencil;
5913 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5914 /* should we be calling the parent or the wined3d surface? */
5915 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5916 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5917 hr = WINED3D_OK;
5919 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5920 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5927 return hr;
5930 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5931 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5933 /* TODO: the use of Impl is deprecated. */
5934 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5935 WINED3DLOCKED_RECT lockedRect;
5937 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5939 /* some basic validation checks */
5940 if(This->cursorTexture) {
5941 ENTER_GL();
5942 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5943 glDeleteTextures(1, &This->cursorTexture);
5944 LEAVE_GL();
5945 This->cursorTexture = 0;
5948 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5949 This->haveHardwareCursor = TRUE;
5950 else
5951 This->haveHardwareCursor = FALSE;
5953 if(pCursorBitmap) {
5954 WINED3DLOCKED_RECT rect;
5956 /* MSDN: Cursor must be A8R8G8B8 */
5957 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5958 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5959 return WINED3DERR_INVALIDCALL;
5962 /* MSDN: Cursor must be smaller than the display mode */
5963 if(pSur->currentDesc.Width > This->ddraw_width ||
5964 pSur->currentDesc.Height > This->ddraw_height) {
5965 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5966 return WINED3DERR_INVALIDCALL;
5969 if (!This->haveHardwareCursor) {
5970 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5972 /* Do not store the surface's pointer because the application may
5973 * release it after setting the cursor image. Windows doesn't
5974 * addref the set surface, so we can't do this either without
5975 * creating circular refcount dependencies. Copy out the gl texture
5976 * instead.
5978 This->cursorWidth = pSur->currentDesc.Width;
5979 This->cursorHeight = pSur->currentDesc.Height;
5980 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5982 const GlPixelFormatDesc *glDesc;
5983 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
5984 char *mem, *bits = (char *)rect.pBits;
5985 GLint intfmt = glDesc->glInternal;
5986 GLint format = glDesc->glFormat;
5987 GLint type = glDesc->glType;
5988 INT height = This->cursorHeight;
5989 INT width = This->cursorWidth;
5990 INT bpp = tableEntry->bpp;
5991 INT i;
5993 /* Reformat the texture memory (pitch and width can be
5994 * different) */
5995 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5996 for(i = 0; i < height; i++)
5997 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5998 IWineD3DSurface_UnlockRect(pCursorBitmap);
5999 ENTER_GL();
6001 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6002 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6003 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6006 /* Make sure that a proper texture unit is selected */
6007 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6008 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6009 checkGLcall("glActiveTextureARB");
6011 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6012 /* Create a new cursor texture */
6013 glGenTextures(1, &This->cursorTexture);
6014 checkGLcall("glGenTextures");
6015 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6016 checkGLcall("glBindTexture");
6017 /* Copy the bitmap memory into the cursor texture */
6018 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6019 HeapFree(GetProcessHeap(), 0, mem);
6020 checkGLcall("glTexImage2D");
6022 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6023 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6024 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6027 LEAVE_GL();
6029 else
6031 FIXME("A cursor texture was not returned.\n");
6032 This->cursorTexture = 0;
6035 else
6037 /* Draw a hardware cursor */
6038 ICONINFO cursorInfo;
6039 HCURSOR cursor;
6040 /* Create and clear maskBits because it is not needed for
6041 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6042 * chunks. */
6043 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6044 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6045 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6046 WINED3DLOCK_NO_DIRTY_UPDATE |
6047 WINED3DLOCK_READONLY
6049 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6050 pSur->currentDesc.Height);
6052 cursorInfo.fIcon = FALSE;
6053 cursorInfo.xHotspot = XHotSpot;
6054 cursorInfo.yHotspot = YHotSpot;
6055 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6056 pSur->currentDesc.Height, 1,
6057 1, &maskBits);
6058 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6059 pSur->currentDesc.Height, 1,
6060 32, lockedRect.pBits);
6061 IWineD3DSurface_UnlockRect(pCursorBitmap);
6062 /* Create our cursor and clean up. */
6063 cursor = CreateIconIndirect(&cursorInfo);
6064 SetCursor(cursor);
6065 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6066 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6067 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6068 This->hardwareCursor = cursor;
6069 HeapFree(GetProcessHeap(), 0, maskBits);
6073 This->xHotSpot = XHotSpot;
6074 This->yHotSpot = YHotSpot;
6075 return WINED3D_OK;
6078 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6080 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6082 This->xScreenSpace = XScreenSpace;
6083 This->yScreenSpace = YScreenSpace;
6085 return;
6089 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6091 BOOL oldVisible = This->bCursorVisible;
6092 POINT pt;
6094 TRACE("(%p) : visible(%d)\n", This, bShow);
6097 * When ShowCursor is first called it should make the cursor appear at the OS's last
6098 * known cursor position. Because of this, some applications just repetitively call
6099 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6101 GetCursorPos(&pt);
6102 This->xScreenSpace = pt.x;
6103 This->yScreenSpace = pt.y;
6105 if (This->haveHardwareCursor) {
6106 This->bCursorVisible = bShow;
6107 if (bShow)
6108 SetCursor(This->hardwareCursor);
6109 else
6110 SetCursor(NULL);
6112 else
6114 if (This->cursorTexture)
6115 This->bCursorVisible = bShow;
6118 return oldVisible;
6121 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6123 TRACE("(%p) : state (%u)\n", This, This->state);
6124 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6125 switch (This->state) {
6126 case WINED3D_OK:
6127 return WINED3D_OK;
6128 case WINED3DERR_DEVICELOST:
6130 ResourceList *resourceList = This->resources;
6131 while (NULL != resourceList) {
6132 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6133 return WINED3DERR_DEVICENOTRESET;
6134 resourceList = resourceList->next;
6136 return WINED3DERR_DEVICELOST;
6138 case WINED3DERR_DRIVERINTERNALERROR:
6139 return WINED3DERR_DRIVERINTERNALERROR;
6142 /* Unknown state */
6143 return WINED3DERR_DRIVERINTERNALERROR;
6147 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6149 /** FIXME: Resource tracking needs to be done,
6150 * The closes we can do to this is set the priorities of all managed textures low
6151 * and then reset them.
6152 ***********************************************************/
6153 FIXME("(%p) : stub\n", This);
6154 return WINED3D_OK;
6157 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6158 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6160 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6161 if(surface->Flags & SFLAG_DIBSECTION) {
6162 /* Release the DC */
6163 SelectObject(surface->hDC, surface->dib.holdbitmap);
6164 DeleteDC(surface->hDC);
6165 /* Release the DIB section */
6166 DeleteObject(surface->dib.DIBsection);
6167 surface->dib.bitmap_data = NULL;
6168 surface->resource.allocatedMemory = NULL;
6169 surface->Flags &= ~SFLAG_DIBSECTION;
6171 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6172 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6173 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6174 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6175 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6176 } else {
6177 surface->pow2Width = surface->pow2Height = 1;
6178 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6179 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6181 if(surface->glDescription.textureName) {
6182 ENTER_GL();
6183 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6184 glDeleteTextures(1, &surface->glDescription.textureName);
6185 LEAVE_GL();
6186 surface->glDescription.textureName = 0;
6187 surface->Flags &= ~SFLAG_CLIENT;
6189 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6190 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6191 surface->Flags |= SFLAG_NONPOW2;
6192 } else {
6193 surface->Flags &= ~SFLAG_NONPOW2;
6195 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6196 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6199 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6201 IWineD3DSwapChainImpl *swapchain;
6202 HRESULT hr;
6203 BOOL DisplayModeChanged = FALSE;
6204 WINED3DDISPLAYMODE mode;
6205 TRACE("(%p)\n", This);
6207 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6208 if(FAILED(hr)) {
6209 ERR("Failed to get the first implicit swapchain\n");
6210 return hr;
6213 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6214 * on an existing gl context, so there's no real need for recreation.
6216 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6218 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6220 TRACE("New params:\n");
6221 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6222 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6223 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6224 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6225 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6226 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6227 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6228 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6229 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6230 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6231 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6232 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6233 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6235 /* No special treatment of these parameters. Just store them */
6236 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6237 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6238 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6239 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6241 /* What to do about these? */
6242 if(pPresentationParameters->BackBufferCount != 0 &&
6243 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6244 ERR("Cannot change the back buffer count yet\n");
6246 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6247 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6248 ERR("Cannot change the back buffer format yet\n");
6250 if(pPresentationParameters->hDeviceWindow != NULL &&
6251 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6252 ERR("Cannot change the device window yet\n");
6254 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6255 ERR("What do do about a changed auto depth stencil parameter?\n");
6258 if(pPresentationParameters->Windowed) {
6259 mode.Width = swapchain->orig_width;
6260 mode.Height = swapchain->orig_height;
6261 mode.RefreshRate = 0;
6262 mode.Format = swapchain->presentParms.BackBufferFormat;
6263 } else {
6264 mode.Width = pPresentationParameters->BackBufferWidth;
6265 mode.Height = pPresentationParameters->BackBufferHeight;
6266 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6267 mode.Format = swapchain->presentParms.BackBufferFormat;
6269 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6270 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6271 pPresentationParameters->BackBufferWidth,
6272 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6275 /* Should Width == 800 && Height == 0 set 800x600? */
6276 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6277 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6278 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6280 WINED3DVIEWPORT vp;
6281 int i;
6283 vp.X = 0;
6284 vp.Y = 0;
6285 vp.Width = pPresentationParameters->BackBufferWidth;
6286 vp.Height = pPresentationParameters->BackBufferHeight;
6287 vp.MinZ = 0;
6288 vp.MaxZ = 1;
6290 if(!pPresentationParameters->Windowed) {
6291 DisplayModeChanged = TRUE;
6293 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6294 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6296 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6297 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6298 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6301 /* Now set the new viewport */
6302 IWineD3DDevice_SetViewport(iface, &vp);
6305 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6306 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6307 DisplayModeChanged) {
6309 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6310 if(!pPresentationParameters->Windowed) {
6311 IWineD3DDevice_SetFullscreen(iface, TRUE);
6314 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6316 /* Switching out of fullscreen mode? First set the original res, then change the window */
6317 if(pPresentationParameters->Windowed) {
6318 IWineD3DDevice_SetFullscreen(iface, FALSE);
6320 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6323 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6324 return WINED3D_OK;
6327 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6329 /** FIXME: always true at the moment **/
6330 if(!bEnableDialogs) {
6331 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6333 return WINED3D_OK;
6337 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6339 TRACE("(%p) : pParameters %p\n", This, pParameters);
6341 *pParameters = This->createParms;
6342 return WINED3D_OK;
6345 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6346 IWineD3DSwapChain *swapchain;
6347 HRESULT hrc = WINED3D_OK;
6349 TRACE("Relaying to swapchain\n");
6351 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6352 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6353 IWineD3DSwapChain_Release(swapchain);
6355 return;
6358 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6359 IWineD3DSwapChain *swapchain;
6360 HRESULT hrc = WINED3D_OK;
6362 TRACE("Relaying to swapchain\n");
6364 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6365 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6366 IWineD3DSwapChain_Release(swapchain);
6368 return;
6372 /** ********************************************************
6373 * Notification functions
6374 ** ********************************************************/
6375 /** This function must be called in the release of a resource when ref == 0,
6376 * the contents of resource must still be correct,
6377 * any handels to other resource held by the caller must be closed
6378 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6379 *****************************************************/
6380 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6382 ResourceList* resourceList;
6384 TRACE("(%p) : resource %p\n", This, resource);
6385 /* add a new texture to the frot of the linked list */
6386 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6387 resourceList->resource = resource;
6389 /* Get the old head */
6390 resourceList->next = This->resources;
6392 This->resources = resourceList;
6393 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6395 return;
6398 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6400 ResourceList* resourceList = NULL;
6401 ResourceList* previousResourceList = NULL;
6403 TRACE("(%p) : resource %p\n", This, resource);
6405 resourceList = This->resources;
6407 while (resourceList != NULL) {
6408 if(resourceList->resource == resource) break;
6409 previousResourceList = resourceList;
6410 resourceList = resourceList->next;
6413 if (resourceList == NULL) {
6414 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6415 return;
6416 } else {
6417 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6419 /* make sure we don't leave a hole in the list */
6420 if (previousResourceList != NULL) {
6421 previousResourceList->next = resourceList->next;
6422 } else {
6423 This->resources = resourceList->next;
6426 return;
6430 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6432 int counter;
6434 TRACE("(%p) : resource %p\n", This, resource);
6435 switch(IWineD3DResource_GetType(resource)){
6436 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6437 case WINED3DRTYPE_SURFACE: {
6438 unsigned int i;
6440 /* Cleanup any FBO attachments if d3d is enabled */
6441 if(This->d3d_initialized) {
6442 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6443 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6444 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6445 set_render_target_fbo(iface, i, NULL);
6446 This->fbo_color_attachments[i] = NULL;
6449 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6450 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6451 set_depth_stencil_fbo(iface, NULL);
6452 This->fbo_depth_attachment = NULL;
6456 break;
6458 case WINED3DRTYPE_TEXTURE:
6459 case WINED3DRTYPE_CUBETEXTURE:
6460 case WINED3DRTYPE_VOLUMETEXTURE:
6461 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6462 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6463 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6464 This->stateBlock->textures[counter] = NULL;
6466 if (This->updateStateBlock != This->stateBlock ){
6467 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6468 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6469 This->updateStateBlock->textures[counter] = NULL;
6473 break;
6474 case WINED3DRTYPE_VOLUME:
6475 /* TODO: nothing really? */
6476 break;
6477 case WINED3DRTYPE_VERTEXBUFFER:
6478 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6480 int streamNumber;
6481 TRACE("Cleaning up stream pointers\n");
6483 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6484 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6485 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6487 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6488 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6489 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6490 This->updateStateBlock->streamSource[streamNumber] = 0;
6491 /* Set changed flag? */
6494 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6495 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6496 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6497 This->stateBlock->streamSource[streamNumber] = 0;
6500 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6501 else { /* This shouldn't happen */
6502 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6504 #endif
6508 break;
6509 case WINED3DRTYPE_INDEXBUFFER:
6510 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6511 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6512 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6513 This->updateStateBlock->pIndexData = NULL;
6516 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6517 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6518 This->stateBlock->pIndexData = NULL;
6522 break;
6523 default:
6524 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6525 break;
6529 /* Remove the resoruce from the resourceStore */
6530 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6532 TRACE("Resource released\n");
6536 /**********************************************************
6537 * IWineD3DDevice VTbl follows
6538 **********************************************************/
6540 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6542 /*** IUnknown methods ***/
6543 IWineD3DDeviceImpl_QueryInterface,
6544 IWineD3DDeviceImpl_AddRef,
6545 IWineD3DDeviceImpl_Release,
6546 /*** IWineD3DDevice methods ***/
6547 IWineD3DDeviceImpl_GetParent,
6548 /*** Creation methods**/
6549 IWineD3DDeviceImpl_CreateVertexBuffer,
6550 IWineD3DDeviceImpl_CreateIndexBuffer,
6551 IWineD3DDeviceImpl_CreateStateBlock,
6552 IWineD3DDeviceImpl_CreateSurface,
6553 IWineD3DDeviceImpl_CreateTexture,
6554 IWineD3DDeviceImpl_CreateVolumeTexture,
6555 IWineD3DDeviceImpl_CreateVolume,
6556 IWineD3DDeviceImpl_CreateCubeTexture,
6557 IWineD3DDeviceImpl_CreateQuery,
6558 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6559 IWineD3DDeviceImpl_CreateVertexDeclaration,
6560 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6561 IWineD3DDeviceImpl_CreateVertexShader,
6562 IWineD3DDeviceImpl_CreatePixelShader,
6563 IWineD3DDeviceImpl_CreatePalette,
6564 /*** Odd functions **/
6565 IWineD3DDeviceImpl_Init3D,
6566 IWineD3DDeviceImpl_Uninit3D,
6567 IWineD3DDeviceImpl_SetFullscreen,
6568 IWineD3DDeviceImpl_SetMultithreaded,
6569 IWineD3DDeviceImpl_EvictManagedResources,
6570 IWineD3DDeviceImpl_GetAvailableTextureMem,
6571 IWineD3DDeviceImpl_GetBackBuffer,
6572 IWineD3DDeviceImpl_GetCreationParameters,
6573 IWineD3DDeviceImpl_GetDeviceCaps,
6574 IWineD3DDeviceImpl_GetDirect3D,
6575 IWineD3DDeviceImpl_GetDisplayMode,
6576 IWineD3DDeviceImpl_SetDisplayMode,
6577 IWineD3DDeviceImpl_GetHWND,
6578 IWineD3DDeviceImpl_SetHWND,
6579 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6580 IWineD3DDeviceImpl_GetRasterStatus,
6581 IWineD3DDeviceImpl_GetSwapChain,
6582 IWineD3DDeviceImpl_Reset,
6583 IWineD3DDeviceImpl_SetDialogBoxMode,
6584 IWineD3DDeviceImpl_SetCursorProperties,
6585 IWineD3DDeviceImpl_SetCursorPosition,
6586 IWineD3DDeviceImpl_ShowCursor,
6587 IWineD3DDeviceImpl_TestCooperativeLevel,
6588 /*** Getters and setters **/
6589 IWineD3DDeviceImpl_SetClipPlane,
6590 IWineD3DDeviceImpl_GetClipPlane,
6591 IWineD3DDeviceImpl_SetClipStatus,
6592 IWineD3DDeviceImpl_GetClipStatus,
6593 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6594 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6595 IWineD3DDeviceImpl_SetDepthStencilSurface,
6596 IWineD3DDeviceImpl_GetDepthStencilSurface,
6597 IWineD3DDeviceImpl_SetFVF,
6598 IWineD3DDeviceImpl_GetFVF,
6599 IWineD3DDeviceImpl_SetGammaRamp,
6600 IWineD3DDeviceImpl_GetGammaRamp,
6601 IWineD3DDeviceImpl_SetIndices,
6602 IWineD3DDeviceImpl_GetIndices,
6603 IWineD3DDeviceImpl_SetBaseVertexIndex,
6604 IWineD3DDeviceImpl_GetBaseVertexIndex,
6605 IWineD3DDeviceImpl_SetLight,
6606 IWineD3DDeviceImpl_GetLight,
6607 IWineD3DDeviceImpl_SetLightEnable,
6608 IWineD3DDeviceImpl_GetLightEnable,
6609 IWineD3DDeviceImpl_SetMaterial,
6610 IWineD3DDeviceImpl_GetMaterial,
6611 IWineD3DDeviceImpl_SetNPatchMode,
6612 IWineD3DDeviceImpl_GetNPatchMode,
6613 IWineD3DDeviceImpl_SetPaletteEntries,
6614 IWineD3DDeviceImpl_GetPaletteEntries,
6615 IWineD3DDeviceImpl_SetPixelShader,
6616 IWineD3DDeviceImpl_GetPixelShader,
6617 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6618 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6619 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6620 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6621 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6622 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6623 IWineD3DDeviceImpl_SetRenderState,
6624 IWineD3DDeviceImpl_GetRenderState,
6625 IWineD3DDeviceImpl_SetRenderTarget,
6626 IWineD3DDeviceImpl_GetRenderTarget,
6627 IWineD3DDeviceImpl_SetFrontBackBuffers,
6628 IWineD3DDeviceImpl_SetSamplerState,
6629 IWineD3DDeviceImpl_GetSamplerState,
6630 IWineD3DDeviceImpl_SetScissorRect,
6631 IWineD3DDeviceImpl_GetScissorRect,
6632 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6633 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6634 IWineD3DDeviceImpl_SetStreamSource,
6635 IWineD3DDeviceImpl_GetStreamSource,
6636 IWineD3DDeviceImpl_SetStreamSourceFreq,
6637 IWineD3DDeviceImpl_GetStreamSourceFreq,
6638 IWineD3DDeviceImpl_SetTexture,
6639 IWineD3DDeviceImpl_GetTexture,
6640 IWineD3DDeviceImpl_SetTextureStageState,
6641 IWineD3DDeviceImpl_GetTextureStageState,
6642 IWineD3DDeviceImpl_SetTransform,
6643 IWineD3DDeviceImpl_GetTransform,
6644 IWineD3DDeviceImpl_SetVertexDeclaration,
6645 IWineD3DDeviceImpl_GetVertexDeclaration,
6646 IWineD3DDeviceImpl_SetVertexShader,
6647 IWineD3DDeviceImpl_GetVertexShader,
6648 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6649 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6650 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6651 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6652 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6653 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6654 IWineD3DDeviceImpl_SetViewport,
6655 IWineD3DDeviceImpl_GetViewport,
6656 IWineD3DDeviceImpl_MultiplyTransform,
6657 IWineD3DDeviceImpl_ValidateDevice,
6658 IWineD3DDeviceImpl_ProcessVertices,
6659 /*** State block ***/
6660 IWineD3DDeviceImpl_BeginStateBlock,
6661 IWineD3DDeviceImpl_EndStateBlock,
6662 /*** Scene management ***/
6663 IWineD3DDeviceImpl_BeginScene,
6664 IWineD3DDeviceImpl_EndScene,
6665 IWineD3DDeviceImpl_Present,
6666 IWineD3DDeviceImpl_Clear,
6667 /*** Drawing ***/
6668 IWineD3DDeviceImpl_DrawPrimitive,
6669 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6670 IWineD3DDeviceImpl_DrawPrimitiveUP,
6671 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6672 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6673 IWineD3DDeviceImpl_DrawRectPatch,
6674 IWineD3DDeviceImpl_DrawTriPatch,
6675 IWineD3DDeviceImpl_DeletePatch,
6676 IWineD3DDeviceImpl_ColorFill,
6677 IWineD3DDeviceImpl_UpdateTexture,
6678 IWineD3DDeviceImpl_UpdateSurface,
6679 IWineD3DDeviceImpl_GetFrontBufferData,
6680 /*** object tracking ***/
6681 IWineD3DDeviceImpl_ResourceReleased
6685 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6686 WINED3DRS_ALPHABLENDENABLE ,
6687 WINED3DRS_ALPHAFUNC ,
6688 WINED3DRS_ALPHAREF ,
6689 WINED3DRS_ALPHATESTENABLE ,
6690 WINED3DRS_BLENDOP ,
6691 WINED3DRS_COLORWRITEENABLE ,
6692 WINED3DRS_DESTBLEND ,
6693 WINED3DRS_DITHERENABLE ,
6694 WINED3DRS_FILLMODE ,
6695 WINED3DRS_FOGDENSITY ,
6696 WINED3DRS_FOGEND ,
6697 WINED3DRS_FOGSTART ,
6698 WINED3DRS_LASTPIXEL ,
6699 WINED3DRS_SHADEMODE ,
6700 WINED3DRS_SRCBLEND ,
6701 WINED3DRS_STENCILENABLE ,
6702 WINED3DRS_STENCILFAIL ,
6703 WINED3DRS_STENCILFUNC ,
6704 WINED3DRS_STENCILMASK ,
6705 WINED3DRS_STENCILPASS ,
6706 WINED3DRS_STENCILREF ,
6707 WINED3DRS_STENCILWRITEMASK ,
6708 WINED3DRS_STENCILZFAIL ,
6709 WINED3DRS_TEXTUREFACTOR ,
6710 WINED3DRS_WRAP0 ,
6711 WINED3DRS_WRAP1 ,
6712 WINED3DRS_WRAP2 ,
6713 WINED3DRS_WRAP3 ,
6714 WINED3DRS_WRAP4 ,
6715 WINED3DRS_WRAP5 ,
6716 WINED3DRS_WRAP6 ,
6717 WINED3DRS_WRAP7 ,
6718 WINED3DRS_ZENABLE ,
6719 WINED3DRS_ZFUNC ,
6720 WINED3DRS_ZWRITEENABLE
6723 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6724 WINED3DTSS_ADDRESSW ,
6725 WINED3DTSS_ALPHAARG0 ,
6726 WINED3DTSS_ALPHAARG1 ,
6727 WINED3DTSS_ALPHAARG2 ,
6728 WINED3DTSS_ALPHAOP ,
6729 WINED3DTSS_BUMPENVLOFFSET ,
6730 WINED3DTSS_BUMPENVLSCALE ,
6731 WINED3DTSS_BUMPENVMAT00 ,
6732 WINED3DTSS_BUMPENVMAT01 ,
6733 WINED3DTSS_BUMPENVMAT10 ,
6734 WINED3DTSS_BUMPENVMAT11 ,
6735 WINED3DTSS_COLORARG0 ,
6736 WINED3DTSS_COLORARG1 ,
6737 WINED3DTSS_COLORARG2 ,
6738 WINED3DTSS_COLOROP ,
6739 WINED3DTSS_RESULTARG ,
6740 WINED3DTSS_TEXCOORDINDEX ,
6741 WINED3DTSS_TEXTURETRANSFORMFLAGS
6744 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6745 WINED3DSAMP_ADDRESSU ,
6746 WINED3DSAMP_ADDRESSV ,
6747 WINED3DSAMP_ADDRESSW ,
6748 WINED3DSAMP_BORDERCOLOR ,
6749 WINED3DSAMP_MAGFILTER ,
6750 WINED3DSAMP_MINFILTER ,
6751 WINED3DSAMP_MIPFILTER ,
6752 WINED3DSAMP_MIPMAPLODBIAS ,
6753 WINED3DSAMP_MAXMIPLEVEL ,
6754 WINED3DSAMP_MAXANISOTROPY ,
6755 WINED3DSAMP_SRGBTEXTURE ,
6756 WINED3DSAMP_ELEMENTINDEX
6759 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6760 WINED3DRS_AMBIENT ,
6761 WINED3DRS_AMBIENTMATERIALSOURCE ,
6762 WINED3DRS_CLIPPING ,
6763 WINED3DRS_CLIPPLANEENABLE ,
6764 WINED3DRS_COLORVERTEX ,
6765 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6766 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6767 WINED3DRS_FOGDENSITY ,
6768 WINED3DRS_FOGEND ,
6769 WINED3DRS_FOGSTART ,
6770 WINED3DRS_FOGTABLEMODE ,
6771 WINED3DRS_FOGVERTEXMODE ,
6772 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6773 WINED3DRS_LIGHTING ,
6774 WINED3DRS_LOCALVIEWER ,
6775 WINED3DRS_MULTISAMPLEANTIALIAS ,
6776 WINED3DRS_MULTISAMPLEMASK ,
6777 WINED3DRS_NORMALIZENORMALS ,
6778 WINED3DRS_PATCHEDGESTYLE ,
6779 WINED3DRS_POINTSCALE_A ,
6780 WINED3DRS_POINTSCALE_B ,
6781 WINED3DRS_POINTSCALE_C ,
6782 WINED3DRS_POINTSCALEENABLE ,
6783 WINED3DRS_POINTSIZE ,
6784 WINED3DRS_POINTSIZE_MAX ,
6785 WINED3DRS_POINTSIZE_MIN ,
6786 WINED3DRS_POINTSPRITEENABLE ,
6787 WINED3DRS_RANGEFOGENABLE ,
6788 WINED3DRS_SPECULARMATERIALSOURCE ,
6789 WINED3DRS_TWEENFACTOR ,
6790 WINED3DRS_VERTEXBLEND
6793 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6794 WINED3DTSS_TEXCOORDINDEX ,
6795 WINED3DTSS_TEXTURETRANSFORMFLAGS
6798 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6799 WINED3DSAMP_DMAPOFFSET
6802 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6803 DWORD rep = StateTable[state].representative;
6804 DWORD idx;
6805 BYTE shift;
6806 UINT i;
6807 WineD3DContext *context;
6809 if(!rep) return;
6810 for(i = 0; i < This->numContexts; i++) {
6811 context = This->contexts[i];
6812 if(isStateDirty(context, rep)) continue;
6814 context->dirtyArray[context->numDirtyEntries++] = rep;
6815 idx = rep >> 5;
6816 shift = rep & 0x1f;
6817 context->isStateDirty[idx] |= (1 << shift);