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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
262 case WINED3DUSAGE_WRITEONLY:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
473 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
474 object->contained_transform_states[j - 1] = j;
476 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
477 for(j = 0; j < MAX_CONST_I; j++) {
478 object->contained_vs_consts_i[j] = j;
480 object->num_contained_vs_consts_i = MAX_CONST_I;
481 for(j = 0; j < MAX_CONST_B; j++) {
482 object->contained_vs_consts_b[j] = j;
484 object->num_contained_vs_consts_b = MAX_CONST_B;
485 for(j = 0; j < MAX_CONST_I; j++) {
486 object->contained_ps_consts_i[j] = j;
488 object->num_contained_ps_consts_i = MAX_CONST_I;
489 for(j = 0; j < MAX_CONST_B; j++) {
490 object->contained_ps_consts_b[j] = j;
492 object->num_contained_ps_consts_b = MAX_CONST_B;
493 for(i = 0; i < MAX_TEXTURES; i++) {
494 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
495 object->contained_tss_states[object->num_contained_tss_states].stage = i;
496 object->contained_tss_states[object->num_contained_tss_states].state = j;
497 object->num_contained_tss_states++;
501 } else if (Type == WINED3DSBT_PIXELSTATE) {
503 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
504 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
506 object->changed.pixelShader = TRUE;
508 /* Pixel Shader Constants */
509 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
510 object->changed.pixelShaderConstantsF[i] = TRUE;
511 for (i = 0; i < MAX_CONST_B; ++i) {
512 object->contained_ps_consts_b[i] = i;
513 object->changed.pixelShaderConstantsB[i] = TRUE;
515 object->num_contained_ps_consts_b = MAX_CONST_B;
516 for (i = 0; i < MAX_CONST_I; ++i) {
517 object->contained_ps_consts_i[i] = i;
518 object->changed.pixelShaderConstantsI[i] = TRUE;
520 object->num_contained_ps_consts_i = MAX_CONST_I;
522 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
523 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
524 object->contained_render_states[i] = SavedPixelStates_R[i];
526 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
527 for (j = 0; j < MAX_TEXTURES; j++) {
528 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
529 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
530 object->contained_tss_states[object->num_contained_tss_states].stage = j;
531 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
532 object->num_contained_tss_states++;
535 for (j = 0 ; j < 16; j++) {
536 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
538 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
542 } else if (Type == WINED3DSBT_VERTEXSTATE) {
544 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
545 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
547 object->changed.vertexShader = TRUE;
549 /* Vertex Shader Constants */
550 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
551 object->changed.vertexShaderConstantsF[i] = TRUE;
552 for (i = 0; i < MAX_CONST_B; ++i) {
553 object->changed.vertexShaderConstantsB[i] = TRUE;
554 object->contained_vs_consts_b[i] = i;
556 object->num_contained_vs_consts_b = MAX_CONST_B;
557 for (i = 0; i < MAX_CONST_I; ++i) {
558 object->changed.vertexShaderConstantsI[i] = TRUE;
559 object->contained_vs_consts_i[i] = i;
561 object->num_contained_vs_consts_i = MAX_CONST_I;
562 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
563 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
564 object->contained_render_states[i] = SavedVertexStates_R[i];
566 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
567 for (j = 0; j < MAX_TEXTURES; j++) {
568 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
569 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
570 object->contained_tss_states[object->num_contained_tss_states].stage = j;
571 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
572 object->num_contained_tss_states++;
575 for (j = 0 ; j < 16; j++){
576 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
577 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
581 for(j = 0; j < LIGHTMAP_SIZE; j++) {
583 LIST_FOR_EACH(e, &object->lightMap[j]) {
584 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
585 light->changed = TRUE;
586 light->enabledChanged = TRUE;
590 FIXME("Unrecognized state block type %d\n", Type);
593 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
597 /* ************************************
599 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
602 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
604 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.
606 ******************************** */
608 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) {
609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
610 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
611 unsigned int Size = 1;
612 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
613 TRACE("(%p) Create surface\n",This);
615 /** FIXME: Check ranges on the inputs are valid
618 * [in] Quality level. The valid range is between zero and one less than the level
619 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
620 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
621 * values of paired render targets, depth stencil surfaces, and the MultiSample type
623 *******************************/
628 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
630 * If this flag is set, the contents of the depth stencil buffer will be
631 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
632 * with a different depth surface.
634 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
635 ***************************/
637 if(MultisampleQuality < 0) {
638 FIXME("Invalid multisample level %d\n", MultisampleQuality);
639 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
642 if(MultisampleQuality > 0) {
643 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
644 MultisampleQuality=0;
647 /** FIXME: Check that the format is supported
649 *******************************/
651 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
652 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
654 *********************************/
655 if (WINED3DFMT_UNKNOWN == Format) {
657 } else if (Format == WINED3DFMT_DXT1) {
658 /* DXT1 is half byte per pixel */
659 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
661 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
662 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
663 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
665 /* The pitch is a multiple of 4 bytes */
666 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
670 /** Create and initialise the surface resource **/
671 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
672 /* "Standalone" surface */
673 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
675 object->currentDesc.Width = Width;
676 object->currentDesc.Height = Height;
677 object->currentDesc.MultiSampleType = MultiSample;
678 object->currentDesc.MultiSampleQuality = MultisampleQuality;
679 object->glDescription.level = Level;
683 object->Flags |= Discard ? SFLAG_DISCARD : 0;
684 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
685 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
688 if (WINED3DFMT_UNKNOWN != Format) {
689 object->bytesPerPixel = tableEntry->bpp;
691 object->bytesPerPixel = 0;
694 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
696 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
698 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
699 * this function is too deep to need to care about things like this.
700 * Levels need to be checked too, and possibly Type since they all affect what can be done.
701 * ****************************************/
703 case WINED3DPOOL_SCRATCH:
705 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
706 "which are mutually exclusive, setting lockable to TRUE\n");
709 case WINED3DPOOL_SYSTEMMEM:
710 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
711 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
712 case WINED3DPOOL_MANAGED:
713 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
714 "Usage of DYNAMIC which are mutually exclusive, not doing "
715 "anything just telling you.\n");
717 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
718 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
719 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
720 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
723 FIXME("(%p) Unknown pool %d\n", This, Pool);
727 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
728 FIXME("Trying to create a render target that isn't in the default pool\n");
731 /* mark the texture as dirty so that it gets loaded first time around*/
732 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
733 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
734 This, Width, Height, Format, debug_d3dformat(Format),
735 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
737 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
738 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
739 This->ddraw_primary = (IWineD3DSurface *) object;
741 /* Look at the implementation and set the correct Vtable */
744 /* Check if a 3D adapter is available when creating gl surfaces */
746 ERR("OpenGL surfaces are not available without opengl\n");
747 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
748 HeapFree(GetProcessHeap(), 0, object);
749 return WINED3DERR_NOTAVAILABLE;
754 object->lpVtbl = &IWineGDISurface_Vtbl;
758 /* To be sure to catch this */
759 ERR("Unknown requested surface implementation %d!\n", Impl);
760 IWineD3DSurface_Release((IWineD3DSurface *) object);
761 return WINED3DERR_INVALIDCALL;
764 list_init(&object->renderbuffers);
766 /* Call the private setup routine */
767 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
771 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
772 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
773 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
774 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
777 IWineD3DTextureImpl *object;
782 unsigned int pow2Width;
783 unsigned int pow2Height;
786 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
787 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
788 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
790 /* TODO: It should only be possible to create textures for formats
791 that are reported as supported */
792 if (WINED3DFMT_UNKNOWN >= Format) {
793 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
794 return WINED3DERR_INVALIDCALL;
797 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
798 D3DINITIALIZEBASETEXTURE(object->baseTexture);
799 object->width = Width;
800 object->height = Height;
802 /** Non-power2 support **/
803 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
807 /* Find the nearest pow2 match */
808 pow2Width = pow2Height = 1;
809 while (pow2Width < Width) pow2Width <<= 1;
810 while (pow2Height < Height) pow2Height <<= 1;
813 /** FIXME: add support for real non-power-two if it's provided by the video card **/
814 /* Precalculated scaling for 'faked' non power of two texture coords */
815 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
816 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
817 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
819 /* Calculate levels for mip mapping */
821 TRACE("calculating levels %d\n", object->baseTexture.levels);
822 object->baseTexture.levels++;
825 while (tmpW > 1 || tmpH > 1) {
826 tmpW = max(1, tmpW >> 1);
827 tmpH = max(1, tmpH >> 1);
828 object->baseTexture.levels++;
830 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
833 /* Generate all the surfaces */
836 for (i = 0; i < object->baseTexture.levels; i++)
838 /* use the callback to create the texture surface */
839 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
840 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
841 FIXME("Failed to create surface %p\n", object);
843 object->surfaces[i] = NULL;
844 IWineD3DTexture_Release((IWineD3DTexture *)object);
850 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
851 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
852 /* calculate the next mipmap level */
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
857 TRACE("(%p) : Created texture %p\n", This, object);
861 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
862 UINT Width, UINT Height, UINT Depth,
863 UINT Levels, DWORD Usage,
864 WINED3DFORMAT Format, WINED3DPOOL Pool,
865 IWineD3DVolumeTexture **ppVolumeTexture,
866 HANDLE *pSharedHandle, IUnknown *parent,
867 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
870 IWineD3DVolumeTextureImpl *object;
876 /* TODO: It should only be possible to create textures for formats
877 that are reported as supported */
878 if (WINED3DFMT_UNKNOWN >= Format) {
879 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
880 return WINED3DERR_INVALIDCALL;
883 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
884 D3DINITIALIZEBASETEXTURE(object->baseTexture);
886 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
887 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
889 object->width = Width;
890 object->height = Height;
891 object->depth = Depth;
893 /* Calculate levels for mip mapping */
895 object->baseTexture.levels++;
899 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
900 tmpW = max(1, tmpW >> 1);
901 tmpH = max(1, tmpH >> 1);
902 tmpD = max(1, tmpD >> 1);
903 object->baseTexture.levels++;
905 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
908 /* Generate all the surfaces */
913 for (i = 0; i < object->baseTexture.levels; i++)
916 /* Create the volume */
917 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
918 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
921 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
922 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
923 *ppVolumeTexture = NULL;
927 /* Set its container to this object */
928 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
930 /* calcualte the next mipmap level */
931 tmpW = max(1, tmpW >> 1);
932 tmpH = max(1, tmpH >> 1);
933 tmpD = max(1, tmpD >> 1);
936 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
937 TRACE("(%p) : Created volume texture %p\n", This, object);
941 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
942 UINT Width, UINT Height, UINT Depth,
944 WINED3DFORMAT Format, WINED3DPOOL Pool,
945 IWineD3DVolume** ppVolume,
946 HANDLE* pSharedHandle, IUnknown *parent) {
948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
949 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
950 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
952 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
954 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
955 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
957 object->currentDesc.Width = Width;
958 object->currentDesc.Height = Height;
959 object->currentDesc.Depth = Depth;
960 object->bytesPerPixel = formatDesc->bpp;
962 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
963 object->lockable = TRUE;
964 object->locked = FALSE;
965 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
966 object->dirty = TRUE;
968 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
971 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
972 UINT Levels, DWORD Usage,
973 WINED3DFORMAT Format, WINED3DPOOL Pool,
974 IWineD3DCubeTexture **ppCubeTexture,
975 HANDLE *pSharedHandle, IUnknown *parent,
976 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
979 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
983 unsigned int pow2EdgeLength = EdgeLength;
985 /* TODO: It should only be possible to create textures for formats
986 that are reported as supported */
987 if (WINED3DFMT_UNKNOWN >= Format) {
988 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
989 return WINED3DERR_INVALIDCALL;
992 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
993 WARN("(%p) : Tried to create not supported cube texture\n", This);
994 return WINED3DERR_INVALIDCALL;
997 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
998 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1000 TRACE("(%p) Create Cube Texture\n", This);
1002 /** Non-power2 support **/
1004 /* Find the nearest pow2 match */
1006 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1008 object->edgeLength = EdgeLength;
1009 /* TODO: support for native non-power 2 */
1010 /* Precalculated scaling for 'faked' non power of two texture coords */
1011 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1013 /* Calculate levels for mip mapping */
1015 object->baseTexture.levels++;
1018 tmpW = max(1, tmpW >> 1);
1019 object->baseTexture.levels++;
1021 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1024 /* Generate all the surfaces */
1026 for (i = 0; i < object->baseTexture.levels; i++) {
1028 /* Create the 6 faces */
1029 for (j = 0; j < 6; j++) {
1031 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1032 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1034 if(hr!= WINED3D_OK) {
1038 for (l = 0; l < j; l++) {
1039 IWineD3DSurface_Release(object->surfaces[j][i]);
1041 for (k = 0; k < i; k++) {
1042 for (l = 0; l < 6; l++) {
1043 IWineD3DSurface_Release(object->surfaces[l][j]);
1047 FIXME("(%p) Failed to create surface\n",object);
1048 HeapFree(GetProcessHeap(),0,object);
1049 *ppCubeTexture = NULL;
1052 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1053 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1055 tmpW = max(1, tmpW >> 1);
1058 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1059 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1063 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1065 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1066 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1068 /* Just a check to see if we support this type of query */
1070 case WINED3DQUERYTYPE_OCCLUSION:
1071 TRACE("(%p) occlusion query\n", This);
1072 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1075 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1078 case WINED3DQUERYTYPE_EVENT:
1079 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1080 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1081 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1083 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1088 case WINED3DQUERYTYPE_VCACHE:
1089 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1090 case WINED3DQUERYTYPE_VERTEXSTATS:
1091 case WINED3DQUERYTYPE_TIMESTAMP:
1092 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1093 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1094 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1095 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1096 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1097 case WINED3DQUERYTYPE_PIXELTIMINGS:
1098 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1099 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1101 FIXME("(%p) Unhandled query type %d\n", This, Type);
1103 if(NULL == ppQuery || hr != WINED3D_OK) {
1107 D3DCREATEOBJECTINSTANCE(object, Query)
1108 object->type = Type;
1109 /* allocated the 'extended' data based on the type of query requested */
1111 case WINED3DQUERYTYPE_OCCLUSION:
1112 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1113 TRACE("(%p) Allocating data for an occlusion query\n", This);
1114 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1115 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1118 case WINED3DQUERYTYPE_EVENT:
1119 /* TODO: GL_APPLE_fence */
1120 if(GL_SUPPORT(APPLE_FENCE)) {
1121 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1122 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1123 checkGLcall("glGenFencesAPPLE");
1124 } else if(GL_SUPPORT(NV_FENCE)) {
1125 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1126 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1127 checkGLcall("glGenFencesNV");
1131 case WINED3DQUERYTYPE_VCACHE:
1132 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1133 case WINED3DQUERYTYPE_VERTEXSTATS:
1134 case WINED3DQUERYTYPE_TIMESTAMP:
1135 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1136 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1137 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1138 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1139 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1140 case WINED3DQUERYTYPE_PIXELTIMINGS:
1141 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1142 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1144 object->extendedData = 0;
1145 FIXME("(%p) Unhandled query type %d\n",This , Type);
1147 TRACE("(%p) : Created Query %p\n", This, object);
1151 /*****************************************************************************
1152 * IWineD3DDeviceImpl_SetupFullscreenWindow
1154 * Helper function that modifies a HWND's Style and ExStyle for proper
1158 * iface: Pointer to the IWineD3DDevice interface
1159 * window: Window to setup
1161 *****************************************************************************/
1162 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1165 LONG style, exStyle;
1166 /* Don't do anything if an original style is stored.
1167 * That shouldn't happen
1169 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1170 if (This->style || This->exStyle) {
1171 ERR("(%p): Want to change the window parameters of HWND %p, but "
1172 "another style is stored for restoration afterwards\n", This, window);
1175 /* Get the parameters and save them */
1176 style = GetWindowLongW(window, GWL_STYLE);
1177 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1178 This->style = style;
1179 This->exStyle = exStyle;
1181 /* Filter out window decorations */
1182 style &= ~WS_CAPTION;
1183 style &= ~WS_THICKFRAME;
1184 exStyle &= ~WS_EX_WINDOWEDGE;
1185 exStyle &= ~WS_EX_CLIENTEDGE;
1187 /* Make sure the window is managed, otherwise we won't get keyboard input */
1188 style |= WS_POPUP | WS_SYSMENU;
1190 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1191 This->style, This->exStyle, style, exStyle);
1193 SetWindowLongW(window, GWL_STYLE, style);
1194 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1196 /* Inform the window about the update. */
1197 SetWindowPos(window, HWND_TOP, 0, 0,
1198 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1199 ShowWindow(window, SW_NORMAL);
1202 /*****************************************************************************
1203 * IWineD3DDeviceImpl_RestoreWindow
1205 * Helper function that restores a windows' properties when taking it out
1206 * of fullscreen mode
1209 * iface: Pointer to the IWineD3DDevice interface
1210 * window: Window to setup
1212 *****************************************************************************/
1213 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1216 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1217 * switch, do nothing
1219 if (!This->style && !This->exStyle) return;
1221 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1222 This, window, This->style, This->exStyle);
1224 SetWindowLongW(window, GWL_STYLE, This->style);
1225 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1227 /* Delete the old values */
1231 /* Inform the window about the update */
1232 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1233 0, 0, 0, 0, /* Pos, Size, ignored */
1234 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1237 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1238 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1240 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1241 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1246 HRESULT hr = WINED3D_OK;
1247 IUnknown *bufferParent;
1249 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1251 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1252 * does a device hold a reference to a swap chain giving them a lifetime of the device
1253 * or does the swap chain notify the device of its destruction.
1254 *******************************/
1256 /* Check the params */
1257 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1258 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1259 return WINED3DERR_INVALIDCALL;
1260 } else if (pPresentationParameters->BackBufferCount > 1) {
1261 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");
1264 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1266 /*********************
1267 * Lookup the window Handle and the relating X window handle
1268 ********************/
1270 /* Setup hwnd we are using, plus which display this equates to */
1271 object->win_handle = pPresentationParameters->hDeviceWindow;
1272 if (!object->win_handle) {
1273 object->win_handle = This->createParms.hFocusWindow;
1276 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1277 hDc = GetDC(object->win_handle);
1278 TRACE("Using hDc %p\n", hDc);
1281 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1282 return WINED3DERR_NOTAVAILABLE;
1285 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1286 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1287 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1288 ReleaseDC(object->win_handle, hDc);
1290 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1291 * then the corresponding dimension of the client area of the hDeviceWindow
1292 * (or the focus window, if hDeviceWindow is NULL) is taken.
1293 **********************/
1295 if (pPresentationParameters->Windowed &&
1296 ((pPresentationParameters->BackBufferWidth == 0) ||
1297 (pPresentationParameters->BackBufferHeight == 0))) {
1300 GetClientRect(object->win_handle, &Rect);
1302 if (pPresentationParameters->BackBufferWidth == 0) {
1303 pPresentationParameters->BackBufferWidth = Rect.right;
1304 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1306 if (pPresentationParameters->BackBufferHeight == 0) {
1307 pPresentationParameters->BackBufferHeight = Rect.bottom;
1308 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1312 /* Put the correct figures in the presentation parameters */
1313 TRACE("Copying across presentation parameters\n");
1314 object->presentParms = *pPresentationParameters;
1316 TRACE("calling rendertarget CB\n");
1317 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1319 object->presentParms.BackBufferWidth,
1320 object->presentParms.BackBufferHeight,
1321 object->presentParms.BackBufferFormat,
1322 object->presentParms.MultiSampleType,
1323 object->presentParms.MultiSampleQuality,
1324 TRUE /* Lockable */,
1325 &object->frontBuffer,
1326 NULL /* pShared (always null)*/);
1327 if (object->frontBuffer != NULL) {
1328 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1330 ERR("Failed to create the front buffer\n");
1335 * Create an opengl context for the display visual
1336 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1337 * use different properties after that point in time. FIXME: How to handle when requested format
1338 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1339 * it chooses is identical to the one already being used!
1340 **********************************/
1341 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1343 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1344 if(!object->context)
1345 return E_OUTOFMEMORY;
1346 object->num_contexts = 1;
1349 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1352 if (!object->context[0]) {
1353 ERR("Failed to create a new context\n");
1354 hr = WINED3DERR_NOTAVAILABLE;
1357 TRACE("Context created (HWND=%p, glContext=%p)\n",
1358 object->win_handle, object->context[0]->glCtx);
1361 /*********************
1362 * Windowed / Fullscreen
1363 *******************/
1366 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1367 * so we should really check to see if there is a fullscreen swapchain already
1368 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1369 **************************************/
1371 if (!pPresentationParameters->Windowed) {
1378 /* Get info on the current display setup */
1380 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1383 /* Change the display settings */
1384 memset(&devmode, 0, sizeof(devmode));
1385 devmode.dmSize = sizeof(devmode);
1386 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1387 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1388 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1389 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1390 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1392 /* For GetDisplayMode */
1393 This->ddraw_width = devmode.dmPelsWidth;
1394 This->ddraw_height = devmode.dmPelsHeight;
1395 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1397 IWineD3DDevice_SetFullscreen(iface, TRUE);
1399 /* And finally clip mouse to our screen */
1400 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1401 ClipCursor(&clip_rc);
1404 /*********************
1405 * Create the back, front and stencil buffers
1406 *******************/
1407 if(object->presentParms.BackBufferCount > 0) {
1410 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1411 if(!object->backBuffer) {
1412 ERR("Out of memory\n");
1417 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1418 TRACE("calling rendertarget CB\n");
1419 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1421 object->presentParms.BackBufferWidth,
1422 object->presentParms.BackBufferHeight,
1423 object->presentParms.BackBufferFormat,
1424 object->presentParms.MultiSampleType,
1425 object->presentParms.MultiSampleQuality,
1426 TRUE /* Lockable */,
1427 &object->backBuffer[i],
1428 NULL /* pShared (always null)*/);
1429 if(hr == WINED3D_OK && object->backBuffer[i]) {
1430 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1432 ERR("Cannot create new back buffer\n");
1436 glDrawBuffer(GL_BACK);
1437 checkGLcall("glDrawBuffer(GL_BACK)");
1441 object->backBuffer = NULL;
1443 /* Single buffering - draw to front buffer */
1445 glDrawBuffer(GL_FRONT);
1446 checkGLcall("glDrawBuffer(GL_FRONT)");
1450 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1451 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1452 TRACE("Creating depth stencil buffer\n");
1453 if (This->depthStencilBuffer == NULL ) {
1454 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1456 object->presentParms.BackBufferWidth,
1457 object->presentParms.BackBufferHeight,
1458 object->presentParms.AutoDepthStencilFormat,
1459 object->presentParms.MultiSampleType,
1460 object->presentParms.MultiSampleQuality,
1461 FALSE /* FIXME: Discard */,
1462 &This->depthStencilBuffer,
1463 NULL /* pShared (always null)*/ );
1464 if (This->depthStencilBuffer != NULL)
1465 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1468 /** TODO: A check on width, height and multisample types
1469 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1470 ****************************/
1471 object->wantsDepthStencilBuffer = TRUE;
1473 object->wantsDepthStencilBuffer = FALSE;
1476 TRACE("Created swapchain %p\n", object);
1477 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1481 if (object->backBuffer) {
1483 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1484 if(object->backBuffer[i]) {
1485 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1486 IUnknown_Release(bufferParent); /* once for the get parent */
1487 if (IUnknown_Release(bufferParent) > 0) {
1488 FIXME("(%p) Something's still holding the back buffer\n",This);
1492 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1493 object->backBuffer = NULL;
1495 if(object->context[0])
1496 DestroyContext(This, object->context[0]);
1497 if(object->frontBuffer) {
1498 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1499 IUnknown_Release(bufferParent); /* once for the get parent */
1500 if (IUnknown_Release(bufferParent) > 0) {
1501 FIXME("(%p) Something's still holding the front buffer\n",This);
1504 HeapFree(GetProcessHeap(), 0, object);
1508 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1509 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1511 TRACE("(%p)\n", This);
1513 return This->NumberOfSwapChains;
1516 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1518 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1520 if(iSwapChain < This->NumberOfSwapChains) {
1521 *pSwapChain = This->swapchains[iSwapChain];
1522 IWineD3DSwapChain_AddRef(*pSwapChain);
1523 TRACE("(%p) returning %p\n", This, *pSwapChain);
1526 TRACE("Swapchain out of range\n");
1528 return WINED3DERR_INVALIDCALL;
1533 * Vertex Declaration
1535 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1536 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 IWineD3DVertexDeclarationImpl *object = NULL;
1539 HRESULT hr = WINED3D_OK;
1541 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1542 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1544 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1546 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1551 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1553 unsigned int idx, idx2;
1554 unsigned int offset;
1555 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1556 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1557 BOOL has_blend_idx = has_blend &&
1558 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1559 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1560 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1561 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1562 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1563 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1564 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1566 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1567 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1569 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1570 WINED3DVERTEXELEMENT *elements = NULL;
1573 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1574 if (has_blend_idx) num_blends--;
1576 /* Compute declaration size */
1577 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1578 has_psize + has_diffuse + has_specular + num_textures + 1;
1580 /* convert the declaration */
1581 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1585 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1588 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1589 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1590 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1593 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1594 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1596 elements[idx].UsageIndex = 0;
1599 if (has_blend && (num_blends > 0)) {
1600 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1601 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1603 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1604 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1605 elements[idx].UsageIndex = 0;
1608 if (has_blend_idx) {
1609 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1610 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1611 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1612 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1613 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1615 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1616 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1617 elements[idx].UsageIndex = 0;
1621 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1622 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1623 elements[idx].UsageIndex = 0;
1627 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1628 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1629 elements[idx].UsageIndex = 0;
1633 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1634 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1635 elements[idx].UsageIndex = 0;
1639 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1640 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1641 elements[idx].UsageIndex = 1;
1644 for (idx2 = 0; idx2 < num_textures; idx2++) {
1645 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1646 switch (numcoords) {
1647 case WINED3DFVF_TEXTUREFORMAT1:
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1650 case WINED3DFVF_TEXTUREFORMAT2:
1651 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1653 case WINED3DFVF_TEXTUREFORMAT3:
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1656 case WINED3DFVF_TEXTUREFORMAT4:
1657 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1660 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1661 elements[idx].UsageIndex = idx2;
1665 /* Now compute offsets, and initialize the rest of the fields */
1666 for (idx = 0, offset = 0; idx < size-1; idx++) {
1667 elements[idx].Stream = 0;
1668 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1669 elements[idx].Offset = offset;
1670 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1673 *ppVertexElements = elements;
1677 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1678 WINED3DVERTEXELEMENT* elements = NULL;
1682 size = ConvertFvfToDeclaration(Fvf, &elements);
1683 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1685 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1686 HeapFree(GetProcessHeap(), 0, elements);
1687 if (hr != S_OK) return hr;
1692 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1693 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1696 HRESULT hr = WINED3D_OK;
1697 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1698 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1700 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1702 if (vertex_declaration) {
1703 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1706 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1708 if (WINED3D_OK != hr) {
1709 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1710 IWineD3DVertexShader_Release(*ppVertexShader);
1711 return WINED3DERR_INVALIDCALL;
1717 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1719 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1720 HRESULT hr = WINED3D_OK;
1722 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1723 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1724 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1725 if (WINED3D_OK == hr) {
1726 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1728 WARN("(%p) : Failed to create pixel shader\n", This);
1734 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1736 IWineD3DPaletteImpl *object;
1738 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1740 /* Create the new object */
1741 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1743 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1744 return E_OUTOFMEMORY;
1747 object->lpVtbl = &IWineD3DPalette_Vtbl;
1749 object->Flags = Flags;
1750 object->parent = Parent;
1751 object->wineD3DDevice = This;
1752 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1754 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1757 HeapFree( GetProcessHeap(), 0, object);
1758 return E_OUTOFMEMORY;
1761 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1763 IWineD3DPalette_Release((IWineD3DPalette *) object);
1767 *Palette = (IWineD3DPalette *) object;
1772 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1774 IWineD3DSwapChainImpl *swapchain;
1778 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1779 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1781 /* TODO: Test if OpenGL is compiled in and loaded */
1783 TRACE("(%p) : Creating stateblock\n", This);
1784 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1785 hr = IWineD3DDevice_CreateStateBlock(iface,
1787 (IWineD3DStateBlock **)&This->stateBlock,
1789 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1790 WARN("Failed to create stateblock\n");
1793 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1794 This->updateStateBlock = This->stateBlock;
1795 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1797 hr = allocate_shader_constants(This->updateStateBlock);
1798 if (WINED3D_OK != hr)
1801 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1802 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1803 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1805 /* Initialize the texture unit mapping to a 1:1 mapping */
1806 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1807 if (state < GL_LIMITS(fragment_samplers)) {
1808 This->texUnitMap[state] = state;
1809 This->rev_tex_unit_map[state] = state;
1811 This->texUnitMap[state] = -1;
1812 This->rev_tex_unit_map[state] = -1;
1816 /* Setup the implicit swapchain */
1817 TRACE("Creating implicit swapchain\n");
1818 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1819 if (FAILED(hr) || !swapchain) {
1820 WARN("Failed to create implicit swapchain\n");
1824 This->NumberOfSwapChains = 1;
1825 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1826 if(!This->swapchains) {
1827 ERR("Out of memory!\n");
1828 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1829 return E_OUTOFMEMORY;
1831 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1833 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1835 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1836 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1837 This->render_targets[0] = swapchain->backBuffer[0];
1838 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1841 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1842 This->render_targets[0] = swapchain->frontBuffer;
1843 This->lastActiveRenderTarget = swapchain->frontBuffer;
1845 IWineD3DSurface_AddRef(This->render_targets[0]);
1846 This->activeContext = swapchain->context[0];
1847 This->lastThread = GetCurrentThreadId();
1849 /* Depth Stencil support */
1850 This->stencilBufferTarget = This->depthStencilBuffer;
1851 if (NULL != This->stencilBufferTarget) {
1852 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1855 /* Set up some starting GL setup */
1858 /* Setup all the devices defaults */
1859 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1861 IWineD3DImpl_CheckGraphicsMemory();
1864 { /* Set a default viewport */
1868 vp.Width = pPresentationParameters->BackBufferWidth;
1869 vp.Height = pPresentationParameters->BackBufferHeight;
1872 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1875 /* Initialize the current view state */
1876 This->view_ident = 1;
1877 This->contexts[0]->last_was_rhw = 0;
1878 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1879 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1881 switch(wined3d_settings.offscreen_rendering_mode) {
1884 This->offscreenBuffer = GL_BACK;
1887 case ORM_BACKBUFFER:
1889 if(GL_LIMITS(aux_buffers) > 0) {
1890 TRACE("Using auxilliary buffer for offscreen rendering\n");
1891 This->offscreenBuffer = GL_AUX0;
1893 TRACE("Using back buffer for offscreen rendering\n");
1894 This->offscreenBuffer = GL_BACK;
1899 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1902 /* Clear the screen */
1903 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1904 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1907 This->d3d_initialized = TRUE;
1911 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1915 TRACE("(%p)\n", This);
1917 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1919 /* I don't think that the interface guarants that the device is destroyed from the same thread
1920 * it was created. Thus make sure a context is active for the glDelete* calls
1922 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1924 TRACE("Deleting high order patches\n");
1925 for(i = 0; i < PATCHMAP_SIZE; i++) {
1926 struct list *e1, *e2;
1927 struct WineD3DRectPatch *patch;
1928 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1929 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1930 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1934 /* Delete the pbuffer context if there is any */
1935 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1937 /* Delete the mouse cursor texture */
1938 if(This->cursorTexture) {
1940 glDeleteTextures(1, &This->cursorTexture);
1942 This->cursorTexture = 0;
1945 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1946 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1948 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1949 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1952 /* Release the buffers (with sanity checks)*/
1953 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1954 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1955 if(This->depthStencilBuffer != This->stencilBufferTarget)
1956 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1958 This->stencilBufferTarget = NULL;
1960 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1961 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1962 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1964 TRACE("Setting rendertarget to NULL\n");
1965 This->render_targets[0] = NULL;
1967 if (This->depthStencilBuffer) {
1968 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1969 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1971 This->depthStencilBuffer = NULL;
1974 for(i=0; i < This->NumberOfSwapChains; i++) {
1975 TRACE("Releasing the implicit swapchain %d\n", i);
1976 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1977 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1981 HeapFree(GetProcessHeap(), 0, This->swapchains);
1982 This->swapchains = NULL;
1983 This->NumberOfSwapChains = 0;
1985 /* Release the update stateblock */
1986 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1987 if(This->updateStateBlock != This->stateBlock)
1988 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1990 This->updateStateBlock = NULL;
1992 { /* because were not doing proper internal refcounts releasing the primary state block
1993 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1994 to set this->stateBlock = NULL; first */
1995 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1996 This->stateBlock = NULL;
1998 /* Release the stateblock */
1999 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2000 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2004 HeapFree(GetProcessHeap(), 0, This->render_targets);
2005 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2006 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2007 This->render_targets = NULL;
2008 This->fbo_color_attachments = NULL;
2009 This->draw_buffers = NULL;
2012 This->d3d_initialized = FALSE;
2016 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2018 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2020 /* Setup the window for fullscreen mode */
2021 if(fullscreen && !This->ddraw_fullscreen) {
2022 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2023 } else if(!fullscreen && This->ddraw_fullscreen) {
2024 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2027 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2028 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2029 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2032 This->ddraw_fullscreen = fullscreen;
2035 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2036 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2037 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2039 * There is no way to deactivate thread safety once it is enabled
2041 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2044 /*For now just store the flag(needed in case of ddraw) */
2045 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2050 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2054 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2057 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2059 /* Resize the screen even without a window:
2060 * The app could have unset it with SetCooperativeLevel, but not called
2061 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2062 * but we don't have any hwnd
2065 memset(&devmode, 0, sizeof(devmode));
2066 devmode.dmSize = sizeof(devmode);
2067 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2068 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2069 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2070 devmode.dmPelsWidth = pMode->Width;
2071 devmode.dmPelsHeight = pMode->Height;
2073 devmode.dmDisplayFrequency = pMode->RefreshRate;
2074 if (pMode->RefreshRate != 0) {
2075 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2078 /* Only change the mode if necessary */
2079 if( (This->ddraw_width == pMode->Width) &&
2080 (This->ddraw_height == pMode->Height) &&
2081 (This->ddraw_format == pMode->Format) &&
2082 (pMode->RefreshRate == 0) ) {
2086 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2087 if (ret != DISP_CHANGE_SUCCESSFUL) {
2088 if(devmode.dmDisplayFrequency != 0) {
2089 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2090 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2091 devmode.dmDisplayFrequency = 0;
2092 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2094 if(ret != DISP_CHANGE_SUCCESSFUL) {
2095 return WINED3DERR_NOTAVAILABLE;
2099 /* Store the new values */
2100 This->ddraw_width = pMode->Width;
2101 This->ddraw_height = pMode->Height;
2102 This->ddraw_format = pMode->Format;
2104 /* Only do this with a window of course */
2105 if(This->ddraw_window)
2106 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2108 /* And finally clip mouse to our screen */
2109 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2110 ClipCursor(&clip_rc);
2115 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2117 *ppD3D= This->wineD3D;
2118 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2119 IWineD3D_AddRef(*ppD3D);
2123 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2124 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2125 * into the video ram as possible and seeing how many fit
2126 * you can also get the correct initial value from nvidia and ATI's driver via X
2127 * texture memory is video memory + AGP memory
2128 *******************/
2129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2130 static BOOL showfixmes = TRUE;
2132 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2133 (wined3d_settings.emulated_textureram/(1024*1024)),
2134 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2137 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2138 (wined3d_settings.emulated_textureram/(1024*1024)),
2139 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2140 /* return simulated texture memory left */
2141 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2149 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2152 /* Update the current state block */
2153 This->updateStateBlock->changed.fvf = TRUE;
2155 if(This->updateStateBlock->fvf == fvf) {
2156 TRACE("Application is setting the old fvf over, nothing to do\n");
2160 This->updateStateBlock->fvf = fvf;
2161 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2167 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2170 *pfvf = This->stateBlock->fvf;
2175 * Get / Set Stream Source
2177 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2179 IWineD3DVertexBuffer *oldSrc;
2181 if (StreamNumber >= MAX_STREAMS) {
2182 WARN("Stream out of range %d\n", StreamNumber);
2183 return WINED3DERR_INVALIDCALL;
2186 oldSrc = This->stateBlock->streamSource[StreamNumber];
2187 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2189 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2191 if(oldSrc == pStreamData &&
2192 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2193 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2194 TRACE("Application is setting the old values over, nothing to do\n");
2198 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2200 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2201 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2204 /* Handle recording of state blocks */
2205 if (This->isRecordingState) {
2206 TRACE("Recording... not performing anything\n");
2210 /* Need to do a getParent and pass the reffs up */
2211 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2212 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2213 so for now, just count internally */
2214 if (pStreamData != NULL) {
2215 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2216 InterlockedIncrement(&vbImpl->bindCount);
2218 if (oldSrc != NULL) {
2219 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2227 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2230 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2231 This->stateBlock->streamSource[StreamNumber],
2232 This->stateBlock->streamOffset[StreamNumber],
2233 This->stateBlock->streamStride[StreamNumber]);
2235 if (StreamNumber >= MAX_STREAMS) {
2236 WARN("Stream out of range %d\n", StreamNumber);
2237 return WINED3DERR_INVALIDCALL;
2239 *pStream = This->stateBlock->streamSource[StreamNumber];
2240 *pStride = This->stateBlock->streamStride[StreamNumber];
2242 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2245 if (*pStream != NULL) {
2246 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2251 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2254 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2256 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2257 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2259 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2260 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2262 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2263 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2270 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2273 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2274 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2276 TRACE("(%p) : returning %d\n", This, *Divider);
2282 * Get / Set & Multiply Transform
2284 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2287 /* Most of this routine, comments included copied from ddraw tree initially: */
2288 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2290 /* Handle recording of state blocks */
2291 if (This->isRecordingState) {
2292 TRACE("Recording... not performing anything\n");
2293 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2294 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2299 * If the new matrix is the same as the current one,
2300 * we cut off any further processing. this seems to be a reasonable
2301 * optimization because as was noticed, some apps (warcraft3 for example)
2302 * tend towards setting the same matrix repeatedly for some reason.
2304 * From here on we assume that the new matrix is different, wherever it matters.
2306 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2307 TRACE("The app is setting the same matrix over again\n");
2310 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2314 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2315 where ViewMat = Camera space, WorldMat = world space.
2317 In OpenGL, camera and world space is combined into GL_MODELVIEW
2318 matrix. The Projection matrix stay projection matrix.
2321 /* Capture the times we can just ignore the change for now */
2322 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2323 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2324 /* Handled by the state manager */
2327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2334 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2338 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2339 WINED3DMATRIX *mat = NULL;
2342 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2343 * below means it will be recorded in a state block change, but it
2344 * works regardless where it is recorded.
2345 * If this is found to be wrong, change to StateBlock.
2347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2348 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2350 if (State < HIGHEST_TRANSFORMSTATE)
2352 mat = &This->updateStateBlock->transforms[State];
2354 FIXME("Unhandled transform state!!\n");
2357 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2359 /* Apply change via set transform - will reapply to eg. lights this way */
2360 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2366 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2367 you can reference any indexes you want as long as that number max are enabled at any
2368 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2369 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2370 but when recording, just build a chain pretty much of commands to be replayed. */
2372 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2374 PLIGHTINFOEL *object = NULL;
2375 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2379 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2381 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2385 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2386 return WINED3DERR_INVALIDCALL;
2389 switch(pLight->Type) {
2390 case WINED3DLIGHT_POINT:
2391 case WINED3DLIGHT_SPOT:
2392 case WINED3DLIGHT_PARALLELPOINT:
2393 case WINED3DLIGHT_GLSPOT:
2394 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2397 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2398 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2399 return WINED3DERR_INVALIDCALL;
2403 case WINED3DLIGHT_DIRECTIONAL:
2404 /* Ignores attenuation */
2408 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2409 return WINED3DERR_INVALIDCALL;
2412 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2413 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2414 if(object->OriginalIndex == Index) break;
2419 TRACE("Adding new light\n");
2420 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2422 ERR("Out of memory error when allocating a light\n");
2423 return E_OUTOFMEMORY;
2425 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2426 object->glIndex = -1;
2427 object->OriginalIndex = Index;
2428 object->changed = TRUE;
2431 /* Initialize the object */
2432 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,
2433 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2434 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2435 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2436 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2437 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2438 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2440 /* Save away the information */
2441 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2443 switch (pLight->Type) {
2444 case WINED3DLIGHT_POINT:
2446 object->lightPosn[0] = pLight->Position.x;
2447 object->lightPosn[1] = pLight->Position.y;
2448 object->lightPosn[2] = pLight->Position.z;
2449 object->lightPosn[3] = 1.0f;
2450 object->cutoff = 180.0f;
2454 case WINED3DLIGHT_DIRECTIONAL:
2456 object->lightPosn[0] = -pLight->Direction.x;
2457 object->lightPosn[1] = -pLight->Direction.y;
2458 object->lightPosn[2] = -pLight->Direction.z;
2459 object->lightPosn[3] = 0.0;
2460 object->exponent = 0.0f;
2461 object->cutoff = 180.0f;
2464 case WINED3DLIGHT_SPOT:
2466 object->lightPosn[0] = pLight->Position.x;
2467 object->lightPosn[1] = pLight->Position.y;
2468 object->lightPosn[2] = pLight->Position.z;
2469 object->lightPosn[3] = 1.0;
2472 object->lightDirn[0] = pLight->Direction.x;
2473 object->lightDirn[1] = pLight->Direction.y;
2474 object->lightDirn[2] = pLight->Direction.z;
2475 object->lightDirn[3] = 1.0;
2478 * opengl-ish and d3d-ish spot lights use too different models for the
2479 * light "intensity" as a function of the angle towards the main light direction,
2480 * so we only can approximate very roughly.
2481 * however spot lights are rather rarely used in games (if ever used at all).
2482 * furthermore if still used, probably nobody pays attention to such details.
2484 if (pLight->Falloff == 0) {
2487 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2489 if (rho < 0.0001) rho = 0.0001f;
2490 object->exponent = -0.3/log(cos(rho/2));
2491 if (object->exponent > 128.0) {
2492 object->exponent = 128.0;
2494 object->cutoff = pLight->Phi*90/M_PI;
2500 FIXME("Unrecognized light type %d\n", pLight->Type);
2503 /* Update the live definitions if the light is currently assigned a glIndex */
2504 if (object->glIndex != -1 && !This->isRecordingState) {
2505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2510 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2511 PLIGHTINFOEL *lightInfo = NULL;
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2515 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2517 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2518 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2519 if(lightInfo->OriginalIndex == Index) break;
2523 if (lightInfo == NULL) {
2524 TRACE("Light information requested but light not defined\n");
2525 return WINED3DERR_INVALIDCALL;
2528 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2533 * Get / Set Light Enable
2534 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2536 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2537 PLIGHTINFOEL *lightInfo = NULL;
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2541 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2543 /* Tests show true = 128...not clear why */
2544 Enable = Enable? 128: 0;
2546 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2547 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2548 if(lightInfo->OriginalIndex == Index) break;
2551 TRACE("Found light: %p\n", lightInfo);
2553 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2554 if (lightInfo == NULL) {
2556 TRACE("Light enabled requested but light not defined, so defining one!\n");
2557 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2559 /* Search for it again! Should be fairly quick as near head of list */
2560 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2561 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2562 if(lightInfo->OriginalIndex == Index) break;
2565 if (lightInfo == NULL) {
2566 FIXME("Adding default lights has failed dismally\n");
2567 return WINED3DERR_INVALIDCALL;
2571 lightInfo->enabledChanged = TRUE;
2573 if(lightInfo->glIndex != -1) {
2574 if(!This->isRecordingState) {
2575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2578 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2579 lightInfo->glIndex = -1;
2581 TRACE("Light already disabled, nothing to do\n");
2584 if (lightInfo->glIndex != -1) {
2586 TRACE("Nothing to do as light was enabled\n");
2589 /* Find a free gl light */
2590 for(i = 0; i < This->maxConcurrentLights; i++) {
2591 if(This->stateBlock->activeLights[i] == NULL) {
2592 This->stateBlock->activeLights[i] = lightInfo;
2593 lightInfo->glIndex = i;
2597 if(lightInfo->glIndex == -1) {
2598 ERR("Too many concurrently active lights\n");
2599 return WINED3DERR_INVALIDCALL;
2602 /* i == lightInfo->glIndex */
2603 if(!This->isRecordingState) {
2604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2612 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2614 PLIGHTINFOEL *lightInfo = NULL;
2615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2617 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2618 TRACE("(%p) : for idx(%d)\n", This, Index);
2620 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2621 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2622 if(lightInfo->OriginalIndex == Index) break;
2626 if (lightInfo == NULL) {
2627 TRACE("Light enabled state requested but light not defined\n");
2628 return WINED3DERR_INVALIDCALL;
2630 /* true is 128 according to SetLightEnable */
2631 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2636 * Get / Set Clip Planes
2638 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2642 /* Validate Index */
2643 if (Index >= GL_LIMITS(clipplanes)) {
2644 TRACE("Application has requested clipplane this device doesn't support\n");
2645 return WINED3DERR_INVALIDCALL;
2648 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2650 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2651 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2652 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2653 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2654 TRACE("Application is setting old values over, nothing to do\n");
2658 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2659 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2660 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2661 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2663 /* Handle recording of state blocks */
2664 if (This->isRecordingState) {
2665 TRACE("Recording... not performing anything\n");
2669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 TRACE("(%p) : for idx %d\n", This, Index);
2678 /* Validate Index */
2679 if (Index >= GL_LIMITS(clipplanes)) {
2680 TRACE("Application has requested clipplane this device doesn't support\n");
2681 return WINED3DERR_INVALIDCALL;
2684 pPlane[0] = This->stateBlock->clipplane[Index][0];
2685 pPlane[1] = This->stateBlock->clipplane[Index][1];
2686 pPlane[2] = This->stateBlock->clipplane[Index][2];
2687 pPlane[3] = This->stateBlock->clipplane[Index][3];
2692 * Get / Set Clip Plane Status
2693 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2695 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 FIXME("(%p) : stub\n", This);
2698 if (NULL == pClipStatus) {
2699 return WINED3DERR_INVALIDCALL;
2701 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2702 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2706 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2708 FIXME("(%p) : stub\n", This);
2709 if (NULL == pClipStatus) {
2710 return WINED3DERR_INVALIDCALL;
2712 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2713 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2718 * Get / Set Material
2720 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 This->updateStateBlock->changed.material = TRUE;
2724 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2726 /* Handle recording of state blocks */
2727 if (This->isRecordingState) {
2728 TRACE("Recording... not performing anything\n");
2732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2736 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2738 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2739 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2740 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2741 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2742 pMaterial->Ambient.b, pMaterial->Ambient.a);
2743 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2744 pMaterial->Specular.b, pMaterial->Specular.a);
2745 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2746 pMaterial->Emissive.b, pMaterial->Emissive.a);
2747 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2755 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2757 IWineD3DIndexBuffer *oldIdxs;
2759 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2760 oldIdxs = This->updateStateBlock->pIndexData;
2762 This->updateStateBlock->changed.indices = TRUE;
2763 This->updateStateBlock->pIndexData = pIndexData;
2765 /* Handle recording of state blocks */
2766 if (This->isRecordingState) {
2767 TRACE("Recording... not performing anything\n");
2771 if(oldIdxs != pIndexData) {
2772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2777 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2780 *ppIndexData = This->stateBlock->pIndexData;
2782 /* up ref count on ppindexdata */
2784 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2785 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2787 TRACE("(%p) No index data set\n", This);
2789 TRACE("Returning %p\n", *ppIndexData);
2794 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 TRACE("(%p)->(%d)\n", This, BaseIndex);
2799 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2800 TRACE("Application is setting the old value over, nothing to do\n");
2804 This->updateStateBlock->baseVertexIndex = BaseIndex;
2806 if (This->isRecordingState) {
2807 TRACE("Recording... not performing anything\n");
2810 /* The base vertex index affects the stream sources */
2811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2815 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 TRACE("(%p) : base_index %p\n", This, base_index);
2819 *base_index = This->stateBlock->baseVertexIndex;
2821 TRACE("Returning %u\n", *base_index);
2827 * Get / Set Viewports
2829 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 TRACE("(%p)\n", This);
2833 This->updateStateBlock->changed.viewport = TRUE;
2834 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2836 /* Handle recording of state blocks */
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2842 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2843 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2850 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 TRACE("(%p)\n", This);
2853 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2858 * Get / Set Render States
2859 * TODO: Verify against dx9 definitions
2861 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 DWORD oldValue = This->stateBlock->renderState[State];
2866 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2868 This->updateStateBlock->changed.renderState[State] = TRUE;
2869 This->updateStateBlock->renderState[State] = Value;
2871 /* Handle recording of state blocks */
2872 if (This->isRecordingState) {
2873 TRACE("Recording... not performing anything\n");
2877 /* Compared here and not before the assignment to allow proper stateblock recording */
2878 if(Value == oldValue) {
2879 TRACE("Application is setting the old value over, nothing to do\n");
2881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2890 *pValue = This->stateBlock->renderState[State];
2895 * Get / Set Sampler States
2896 * TODO: Verify against dx9 definitions
2899 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2904 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2906 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2907 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2911 * SetSampler is designed to allow for more than the standard up to 8 textures
2912 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2913 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2915 * http://developer.nvidia.com/object/General_FAQ.html#t6
2917 * There are two new settings for GForce
2919 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2920 * and the texture one:
2921 * GL_MAX_TEXTURE_COORDS_ARB.
2922 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2925 oldValue = This->stateBlock->samplerState[Sampler][Type];
2926 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2927 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2929 /* Handle recording of state blocks */
2930 if (This->isRecordingState) {
2931 TRACE("Recording... not performing anything\n");
2935 if(oldValue == Value) {
2936 TRACE("Application is setting the old value over, nothing to do\n");
2940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2945 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2948 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2949 This, Sampler, debug_d3dsamplerstate(Type), Type);
2951 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2952 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2955 *Value = This->stateBlock->samplerState[Sampler][Type];
2956 TRACE("(%p) : Returning %#x\n", This, *Value);
2961 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 This->updateStateBlock->changed.scissorRect = TRUE;
2965 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2966 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2969 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2971 if(This->isRecordingState) {
2972 TRACE("Recording... not performing anything\n");
2976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2985 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2989 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2991 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2993 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2995 This->updateStateBlock->vertexDecl = pDecl;
2996 This->updateStateBlock->changed.vertexDecl = TRUE;
2998 if (This->isRecordingState) {
2999 TRACE("Recording... not performing anything\n");
3001 } else if(pDecl == oldDecl) {
3002 /* Checked after the assignment to allow proper stateblock recording */
3003 TRACE("Application is setting the old declaration over, nothing to do\n");
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3016 *ppDecl = This->stateBlock->vertexDecl;
3017 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3021 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3023 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3025 This->updateStateBlock->vertexShader = pShader;
3026 This->updateStateBlock->changed.vertexShader = TRUE;
3028 if (This->isRecordingState) {
3029 TRACE("Recording... not performing anything\n");
3031 } else if(oldShader == pShader) {
3032 /* Checked here to allow proper stateblock recording */
3033 TRACE("App is setting the old shader over, nothing to do\n");
3037 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3047 if (NULL == ppShader) {
3048 return WINED3DERR_INVALIDCALL;
3050 *ppShader = This->stateBlock->vertexShader;
3051 if( NULL != *ppShader)
3052 IWineD3DVertexShader_AddRef(*ppShader);
3054 TRACE("(%p) : returning %p\n", This, *ppShader);
3058 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3059 IWineD3DDevice *iface,
3061 CONST BOOL *srcData,
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 int i, cnt = min(count, MAX_CONST_B - start);
3067 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3068 iface, srcData, start, count);
3070 if (srcData == NULL || cnt < 0)
3071 return WINED3DERR_INVALIDCALL;
3073 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3074 for (i = 0; i < cnt; i++)
3075 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3077 for (i = start; i < cnt + start; ++i) {
3078 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3086 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3087 IWineD3DDevice *iface,
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 int cnt = min(count, MAX_CONST_B - start);
3095 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3096 iface, dstData, start, count);
3098 if (dstData == NULL || cnt < 0)
3099 return WINED3DERR_INVALIDCALL;
3101 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3105 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3106 IWineD3DDevice *iface,
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 int i, cnt = min(count, MAX_CONST_I - start);
3114 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3115 iface, srcData, start, count);
3117 if (srcData == NULL || cnt < 0)
3118 return WINED3DERR_INVALIDCALL;
3120 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3121 for (i = 0; i < cnt; i++)
3122 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3123 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3125 for (i = start; i < cnt + start; ++i) {
3126 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3134 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3135 IWineD3DDevice *iface,
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141 int cnt = min(count, MAX_CONST_I - start);
3143 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3144 iface, dstData, start, count);
3146 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3147 return WINED3DERR_INVALIDCALL;
3149 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3153 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3154 IWineD3DDevice *iface,
3156 CONST float *srcData,
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3163 iface, srcData, start, count);
3165 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3166 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3167 return WINED3DERR_INVALIDCALL;
3169 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3171 for (i = 0; i < count; i++)
3172 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3173 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3176 for (i = start; i < count + start; ++i) {
3177 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3178 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3179 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3180 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3181 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3183 ptr->idx[ptr->count++] = i;
3184 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3193 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3194 IWineD3DDevice *iface,
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3200 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3202 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3203 iface, dstData, start, count);
3205 if (dstData == NULL || cnt < 0)
3206 return WINED3DERR_INVALIDCALL;
3208 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3212 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3214 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3219 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3220 int i = This->rev_tex_unit_map[unit];
3221 int j = This->texUnitMap[stage];
3223 This->texUnitMap[stage] = unit;
3224 if (i != -1 && i != stage) {
3225 This->texUnitMap[i] = -1;
3228 This->rev_tex_unit_map[unit] = stage;
3229 if (j != -1 && j != unit) {
3230 This->rev_tex_unit_map[j] = -1;
3234 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3237 for (i = 0; i < MAX_TEXTURES; ++i) {
3238 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3239 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3240 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3241 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3242 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3243 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3244 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3245 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3247 if (color_op == WINED3DTOP_DISABLE) {
3248 /* Not used, and disable higher stages */
3249 while (i < MAX_TEXTURES) {
3250 This->fixed_function_usage_map[i] = FALSE;
3256 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3257 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3258 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3259 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3260 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3261 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3262 This->fixed_function_usage_map[i] = TRUE;
3264 This->fixed_function_usage_map[i] = FALSE;
3267 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3268 This->fixed_function_usage_map[i+1] = TRUE;
3273 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3276 device_update_fixed_function_usage_map(This);
3278 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3279 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3280 if (!This->fixed_function_usage_map[i]) continue;
3282 if (This->texUnitMap[i] != i) {
3283 device_map_stage(This, i, i);
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3285 markTextureStagesDirty(This, i);
3291 /* Now work out the mapping */
3293 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3294 if (!This->fixed_function_usage_map[i]) continue;
3296 if (This->texUnitMap[i] != tex) {
3297 device_map_stage(This, i, tex);
3298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3299 markTextureStagesDirty(This, i);
3306 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3307 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3310 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3311 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3312 device_map_stage(This, i, i);
3313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3314 if (i < MAX_TEXTURES) {
3315 markTextureStagesDirty(This, i);
3321 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3322 int current_mapping = This->rev_tex_unit_map[unit];
3324 if (current_mapping == -1) {
3325 /* Not currently used */
3329 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3330 /* Used by a fragment sampler */
3332 if (!pshader_sampler_tokens) {
3333 /* No pixel shader, check fixed function */
3334 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3337 /* Pixel shader, check the shader's sampler map */
3338 return !pshader_sampler_tokens[current_mapping];
3341 /* Used by a vertex sampler */
3342 return !vshader_sampler_tokens[current_mapping];
3345 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3346 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3347 DWORD *pshader_sampler_tokens = NULL;
3348 int start = GL_LIMITS(combined_samplers) - 1;
3352 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3354 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3355 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3356 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3359 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3360 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3361 if (vshader_sampler_tokens[i]) {
3362 if (This->texUnitMap[vsampler_idx] != -1) {
3363 /* Already mapped somewhere */
3367 while (start >= 0) {
3368 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3369 device_map_stage(This, vsampler_idx, start);
3370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3382 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3383 BOOL vs = use_vs(This);
3384 BOOL ps = use_ps(This);
3387 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3388 * that would be really messy and require shader recompilation
3389 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3390 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3393 device_map_psamplers(This);
3395 device_map_fixed_function_samplers(This);
3399 device_map_vsamplers(This, ps);
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3406 This->updateStateBlock->pixelShader = pShader;
3407 This->updateStateBlock->changed.pixelShader = TRUE;
3409 /* Handle recording of state blocks */
3410 if (This->isRecordingState) {
3411 TRACE("Recording... not performing anything\n");
3414 if (This->isRecordingState) {
3415 TRACE("Recording... not performing anything\n");
3419 if(pShader == oldShader) {
3420 TRACE("App is setting the old pixel shader over, nothing to do\n");
3424 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3430 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 if (NULL == ppShader) {
3434 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3435 return WINED3DERR_INVALIDCALL;
3438 *ppShader = This->stateBlock->pixelShader;
3439 if (NULL != *ppShader) {
3440 IWineD3DPixelShader_AddRef(*ppShader);
3442 TRACE("(%p) : returning %p\n", This, *ppShader);
3446 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3447 IWineD3DDevice *iface,
3449 CONST BOOL *srcData,
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 int i, cnt = min(count, MAX_CONST_B - start);
3455 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3456 iface, srcData, start, count);
3458 if (srcData == NULL || cnt < 0)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3462 for (i = 0; i < cnt; i++)
3463 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3465 for (i = start; i < cnt + start; ++i) {
3466 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3474 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3475 IWineD3DDevice *iface,
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int cnt = min(count, MAX_CONST_B - start);
3483 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3484 iface, dstData, start, count);
3486 if (dstData == NULL || cnt < 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3493 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3494 IWineD3DDevice *iface,
3499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3500 int i, cnt = min(count, MAX_CONST_I - start);
3502 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3503 iface, srcData, start, count);
3505 if (srcData == NULL || cnt < 0)
3506 return WINED3DERR_INVALIDCALL;
3508 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3509 for (i = 0; i < cnt; i++)
3510 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3511 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3513 for (i = start; i < cnt + start; ++i) {
3514 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3522 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3523 IWineD3DDevice *iface,
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);
3541 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3542 IWineD3DDevice *iface,
3544 CONST float *srcData,
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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);
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->changed.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->changed.pixelShaderConstantsF[i] = TRUE;
3576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3581 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3582 IWineD3DDevice *iface,
3587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3588 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3590 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3591 iface, dstData, start, count);
3593 if (dstData == NULL || cnt < 0)
3594 return WINED3DERR_INVALIDCALL;
3596 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3600 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3602 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3603 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3605 DWORD DestFVF = dest->fvf;
3607 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3611 if (lpStrideData->u.s.normal.lpData) {
3612 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3615 if (lpStrideData->u.s.position.lpData == NULL) {
3616 ERR("Source has no position mask\n");
3617 return WINED3DERR_INVALIDCALL;
3620 /* We might access VBOs from this code, so hold the lock */
3623 if (dest->resource.allocatedMemory == NULL) {
3624 /* This may happen if we do direct locking into a vbo. Unlikely,
3625 * but theoretically possible(ddraw processvertices test)
3627 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3628 if(!dest->resource.allocatedMemory) {
3630 ERR("Out of memory\n");
3631 return E_OUTOFMEMORY;
3635 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3636 checkGLcall("glBindBufferARB");
3637 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3639 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3641 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3642 checkGLcall("glUnmapBufferARB");
3646 /* Get a pointer into the destination vbo(create one if none exists) and
3647 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3649 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3654 unsigned char extrabytes = 0;
3655 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3656 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3657 * this may write 4 extra bytes beyond the area that should be written
3659 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3660 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3661 if(!dest_conv_addr) {
3662 ERR("Out of memory\n");
3663 /* Continue without storing converted vertices */
3665 dest_conv = dest_conv_addr;
3669 * a) WINED3DRS_CLIPPING is enabled
3670 * b) WINED3DVOP_CLIP is passed
3672 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3673 static BOOL warned = FALSE;
3675 * The clipping code is not quite correct. Some things need
3676 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3677 * so disable clipping for now.
3678 * (The graphics in Half-Life are broken, and my processvertices
3679 * test crashes with IDirect3DDevice3)
3685 FIXME("Clipping is broken and disabled for now\n");
3687 } else doClip = FALSE;
3688 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3690 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3693 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3694 WINED3DTS_PROJECTION,
3696 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3697 WINED3DTS_WORLDMATRIX(0),
3700 TRACE("View mat:\n");
3701 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);
3702 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);
3703 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);
3704 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);
3706 TRACE("Proj mat:\n");
3707 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);
3708 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);
3709 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);
3710 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);
3712 TRACE("World mat:\n");
3713 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);
3714 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);
3715 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);
3716 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);
3718 /* Get the viewport */
3719 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3720 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3721 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3723 multiply_matrix(&mat,&view_mat,&world_mat);
3724 multiply_matrix(&mat,&proj_mat,&mat);
3726 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3728 for (i = 0; i < dwCount; i+= 1) {
3729 unsigned int tex_index;
3731 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3732 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3733 /* The position first */
3735 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3737 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3739 /* Multiplication with world, view and projection matrix */
3740 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);
3741 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);
3742 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);
3743 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);
3745 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3747 /* WARNING: The following things are taken from d3d7 and were not yet checked
3748 * against d3d8 or d3d9!
3751 /* Clipping conditions: From
3752 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3754 * A vertex is clipped if it does not match the following requirements
3758 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3760 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3761 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3766 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3767 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3770 /* "Normal" viewport transformation (not clipped)
3771 * 1) The values are divided by rhw
3772 * 2) The y axis is negative, so multiply it with -1
3773 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3774 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3775 * 4) Multiply x with Width/2 and add Width/2
3776 * 5) The same for the height
3777 * 6) Add the viewpoint X and Y to the 2D coordinates and
3778 * The minimum Z value to z
3779 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3781 * Well, basically it's simply a linear transformation into viewport
3793 z *= vp.MaxZ - vp.MinZ;
3795 x += vp.Width / 2 + vp.X;
3796 y += vp.Height / 2 + vp.Y;
3801 /* That vertex got clipped
3802 * Contrary to OpenGL it is not dropped completely, it just
3803 * undergoes a different calculation.
3805 TRACE("Vertex got clipped\n");
3812 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3813 * outside of the main vertex buffer memory. That needs some more
3818 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3821 ( (float *) dest_ptr)[0] = x;
3822 ( (float *) dest_ptr)[1] = y;
3823 ( (float *) dest_ptr)[2] = z;
3824 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3826 dest_ptr += 3 * sizeof(float);
3828 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3829 dest_ptr += sizeof(float);
3834 ( (float *) dest_conv)[0] = x * w;
3835 ( (float *) dest_conv)[1] = y * w;
3836 ( (float *) dest_conv)[2] = z * w;
3837 ( (float *) dest_conv)[3] = w;
3839 dest_conv += 3 * sizeof(float);
3841 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3842 dest_conv += sizeof(float);
3846 if (DestFVF & WINED3DFVF_PSIZE) {
3847 dest_ptr += sizeof(DWORD);
3848 if(dest_conv) dest_conv += sizeof(DWORD);
3850 if (DestFVF & WINED3DFVF_NORMAL) {
3852 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3853 /* AFAIK this should go into the lighting information */
3854 FIXME("Didn't expect the destination to have a normal\n");
3855 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3857 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3861 if (DestFVF & WINED3DFVF_DIFFUSE) {
3863 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3865 static BOOL warned = FALSE;
3868 ERR("No diffuse color in source, but destination has one\n");
3872 *( (DWORD *) dest_ptr) = 0xffffffff;
3873 dest_ptr += sizeof(DWORD);
3876 *( (DWORD *) dest_conv) = 0xffffffff;
3877 dest_conv += sizeof(DWORD);
3881 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3883 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3884 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3885 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3886 dest_conv += sizeof(DWORD);
3891 if (DestFVF & WINED3DFVF_SPECULAR) {
3892 /* What's the color value in the feedback buffer? */
3894 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3896 static BOOL warned = FALSE;
3899 ERR("No specular color in source, but destination has one\n");
3903 *( (DWORD *) dest_ptr) = 0xFF000000;
3904 dest_ptr += sizeof(DWORD);
3907 *( (DWORD *) dest_conv) = 0xFF000000;
3908 dest_conv += sizeof(DWORD);
3912 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3914 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3915 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3916 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3917 dest_conv += sizeof(DWORD);
3922 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3924 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3925 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3927 ERR("No source texture, but destination requests one\n");
3928 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3929 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3932 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3934 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3941 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3942 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3943 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3944 dwCount * get_flexible_vertex_size(DestFVF),
3946 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3947 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3954 #undef copy_and_next
3956 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3958 WineDirect3DVertexStridedData strided;
3959 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3960 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3963 ERR("Output vertex declaration not implemented yet\n");
3966 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3967 * and this call is quite performance critical, so don't call needlessly
3969 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3970 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3973 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3974 * control the streamIsUP flag, thus restore it afterwards.
3976 This->stateBlock->streamIsUP = FALSE;
3977 memset(&strided, 0, sizeof(strided));
3978 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3979 This->stateBlock->streamIsUP = streamWasUP;
3981 if(vbo || SrcStartIndex) {
3983 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3984 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3986 * Also get the start index in, but only loop over all elements if there's something to add at all.
3988 #define FIXSRC(type) \
3989 if(strided.u.s.type.VBO) { \
3990 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3991 strided.u.s.type.VBO = 0; \
3992 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3994 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3998 if(strided.u.s.type.lpData) { \
3999 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4002 FIXSRC(blendWeights);
4003 FIXSRC(blendMatrixIndices);
4008 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4009 FIXSRC(texCoords[i]);
4022 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4026 * Get / Set Texture Stage States
4027 * TODO: Verify against dx9 definitions
4029 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4031 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4033 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4035 if (Stage >= MAX_TEXTURES) {
4036 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4040 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4041 This->updateStateBlock->textureState[Stage][Type] = Value;
4043 if (This->isRecordingState) {
4044 TRACE("Recording... not performing anything\n");
4048 /* Checked after the assignments to allow proper stateblock recording */
4049 if(oldValue == Value) {
4050 TRACE("App is setting the old value over, nothing to do\n");
4054 if(Stage > This->stateBlock->lowest_disabled_stage &&
4055 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4056 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4057 * Changes in other states are important on disabled stages too
4062 if(Type == WINED3DTSS_COLOROP) {
4065 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4066 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4067 * they have to be disabled
4069 * The current stage is dirtified below.
4071 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4072 TRACE("Additionally dirtifying stage %d\n", i);
4073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4075 This->stateBlock->lowest_disabled_stage = Stage;
4076 TRACE("New lowest disabled: %d\n", Stage);
4077 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4078 /* Previously disabled stage enabled. Stages above it may need enabling
4079 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4080 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4082 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4085 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4086 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4089 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4092 This->stateBlock->lowest_disabled_stage = i;
4093 TRACE("New lowest disabled: %d\n", i);
4095 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4096 /* TODO: Built a stage -> texture unit mapping for register combiners */
4100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4105 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4107 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4108 *pValue = This->updateStateBlock->textureState[Stage][Type];
4115 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4117 IWineD3DBaseTexture *oldTexture;
4119 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4121 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4122 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4125 oldTexture = This->updateStateBlock->textures[Stage];
4127 if(pTexture != NULL) {
4128 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4130 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4131 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4132 return WINED3DERR_INVALIDCALL;
4134 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4137 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4138 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4140 This->updateStateBlock->changed.textures[Stage] = TRUE;
4141 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4142 This->updateStateBlock->textures[Stage] = pTexture;
4144 /* Handle recording of state blocks */
4145 if (This->isRecordingState) {
4146 TRACE("Recording... not performing anything\n");
4150 if(oldTexture == pTexture) {
4151 TRACE("App is setting the same texture again, nothing to do\n");
4155 /** NOTE: MSDN says that setTexture increases the reference count,
4156 * and the the application must set the texture back to null (or have a leaky application),
4157 * This means we should pass the refcount up to the parent
4158 *******************************/
4159 if (NULL != This->updateStateBlock->textures[Stage]) {
4160 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4161 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4163 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4164 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4165 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4166 * so the COLOROP and ALPHAOP have to be dirtified.
4168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4171 if(bindCount == 1) {
4172 new->baseTexture.sampler = Stage;
4174 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4178 if (NULL != oldTexture) {
4179 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4180 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4182 IWineD3DBaseTexture_Release(oldTexture);
4183 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4188 if(bindCount && old->baseTexture.sampler == Stage) {
4190 /* Have to do a search for the other sampler(s) where the texture is bound to
4191 * Shouldn't happen as long as apps bind a texture only to one stage
4193 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4194 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4195 if(This->updateStateBlock->textures[i] == oldTexture) {
4196 old->baseTexture.sampler = i;
4203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4208 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4211 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4213 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4214 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4217 *ppTexture=This->stateBlock->textures[Stage];
4219 IWineD3DBaseTexture_AddRef(*ppTexture);
4221 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4229 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4230 IWineD3DSurface **ppBackBuffer) {
4231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4232 IWineD3DSwapChain *swapChain;
4235 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4237 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4238 if (hr == WINED3D_OK) {
4239 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4240 IWineD3DSwapChain_Release(swapChain);
4242 *ppBackBuffer = NULL;
4247 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4249 WARN("(%p) : stub, calling idirect3d for now\n", This);
4250 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4253 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4255 IWineD3DSwapChain *swapChain;
4258 if(iSwapChain > 0) {
4259 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4260 if (hr == WINED3D_OK) {
4261 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4262 IWineD3DSwapChain_Release(swapChain);
4264 FIXME("(%p) Error getting display mode\n", This);
4267 /* Don't read the real display mode,
4268 but return the stored mode instead. X11 can't change the color
4269 depth, and some apps are pretty angry if they SetDisplayMode from
4270 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4272 Also don't relay to the swapchain because with ddraw it's possible
4273 that there isn't a swapchain at all */
4274 pMode->Width = This->ddraw_width;
4275 pMode->Height = This->ddraw_height;
4276 pMode->Format = This->ddraw_format;
4277 pMode->RefreshRate = 0;
4284 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4286 TRACE("(%p)->(%p)\n", This, hWnd);
4288 if(This->ddraw_fullscreen) {
4289 if(This->ddraw_window && This->ddraw_window != hWnd) {
4290 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4292 if(hWnd && This->ddraw_window != hWnd) {
4293 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4297 This->ddraw_window = hWnd;
4301 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4303 TRACE("(%p)->(%p)\n", This, hWnd);
4305 *hWnd = This->ddraw_window;
4310 * Stateblock related functions
4313 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4315 IWineD3DStateBlockImpl *object;
4316 HRESULT temp_result;
4319 ERR("(%p)\n", This);
4321 if (This->isRecordingState) {
4322 return WINED3DERR_INVALIDCALL;
4325 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4326 if (NULL == object ) {
4327 FIXME("(%p)Error allocating memory for stateblock\n", This);
4328 return E_OUTOFMEMORY;
4330 TRACE("(%p) created object %p\n", This, object);
4331 object->wineD3DDevice= This;
4332 /** FIXME: object->parent = parent; **/
4333 object->parent = NULL;
4334 object->blockType = WINED3DSBT_ALL;
4336 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4339 list_init(&object->lightMap[i]);
4342 temp_result = allocate_shader_constants(object);
4343 if (WINED3D_OK != temp_result)
4346 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4347 This->updateStateBlock = object;
4348 This->isRecordingState = TRUE;
4350 TRACE("(%p) recording stateblock %p\n",This , object);
4354 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4357 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4359 if (!This->isRecordingState) {
4360 FIXME("(%p) not recording! returning error\n", This);
4361 *ppStateBlock = NULL;
4362 return WINED3DERR_INVALIDCALL;
4365 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4366 if(object->changed.renderState[i]) {
4367 object->contained_render_states[object->num_contained_render_states] = i;
4368 object->num_contained_render_states++;
4371 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4372 if(object->changed.transform[i]) {
4373 object->contained_transform_states[object->num_contained_transform_states] = i;
4374 object->num_contained_transform_states++;
4377 for(i = 0; i < MAX_CONST_I; i++) {
4378 if(object->changed.vertexShaderConstantsI[i]) {
4379 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4380 object->num_contained_vs_consts_i++;
4383 for(i = 0; i < MAX_CONST_B; i++) {
4384 if(object->changed.vertexShaderConstantsB[i]) {
4385 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4386 object->num_contained_vs_consts_b++;
4389 for(i = 0; i < MAX_CONST_I; i++) {
4390 if(object->changed.pixelShaderConstantsI[i]) {
4391 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4392 object->num_contained_ps_consts_i++;
4395 for(i = 0; i < MAX_CONST_B; i++) {
4396 if(object->changed.pixelShaderConstantsB[i]) {
4397 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4398 object->num_contained_ps_consts_b++;
4401 for(i = 0; i < MAX_TEXTURES; i++) {
4402 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4403 if(object->changed.textureState[i][j]) {
4404 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4405 object->contained_tss_states[object->num_contained_tss_states].state = j;
4406 object->num_contained_tss_states++;
4411 *ppStateBlock = (IWineD3DStateBlock*) object;
4412 This->isRecordingState = FALSE;
4413 This->updateStateBlock = This->stateBlock;
4414 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4415 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4416 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4421 * Scene related functions
4423 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4424 /* At the moment we have no need for any functionality at the beginning
4426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4427 TRACE("(%p)\n", This);
4430 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4431 return WINED3DERR_INVALIDCALL;
4433 This->inScene = TRUE;
4437 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 TRACE("(%p)\n", This);
4441 if(!This->inScene) {
4442 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4443 return WINED3DERR_INVALIDCALL;
4446 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4447 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4449 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4452 checkGLcall("glFlush");
4455 This->inScene = FALSE;
4459 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4460 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4461 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4463 IWineD3DSwapChain *swapChain = NULL;
4465 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4467 TRACE("(%p) Presenting the frame\n", This);
4469 for(i = 0 ; i < swapchains ; i ++) {
4471 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4472 TRACE("presentinng chain %d, %p\n", i, swapChain);
4473 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4474 IWineD3DSwapChain_Release(swapChain);
4480 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4481 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4483 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4485 GLbitfield glMask = 0;
4487 CONST WINED3DRECT* curRect;
4489 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4490 Count, pRects, Flags, Color, Z, Stencil);
4492 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4493 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4494 /* TODO: What about depth stencil buffers without stencil bits? */
4495 return WINED3DERR_INVALIDCALL;
4498 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4499 * and not the last active one.
4501 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4504 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4505 apply_fbo_state(iface);
4508 if (Count > 0 && pRects) {
4514 /* Only set the values up once, as they are not changing */
4515 if (Flags & WINED3DCLEAR_STENCIL) {
4516 glClearStencil(Stencil);
4517 checkGLcall("glClearStencil");
4518 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4519 glStencilMask(0xFFFFFFFF);
4522 if (Flags & WINED3DCLEAR_ZBUFFER) {
4523 glDepthMask(GL_TRUE);
4525 checkGLcall("glClearDepth");
4526 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4530 if (Flags & WINED3DCLEAR_TARGET) {
4531 TRACE("Clearing screen with glClear to color %x\n", Color);
4532 glClearColor(D3DCOLOR_R(Color),
4536 checkGLcall("glClearColor");
4538 /* Clear ALL colors! */
4539 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4540 glMask = glMask | GL_COLOR_BUFFER_BIT;
4544 /* In drawable flag is set below */
4546 if (This->render_offscreen) {
4547 glScissor(This->stateBlock->viewport.X,
4548 This->stateBlock->viewport.Y,
4549 This->stateBlock->viewport.Width,
4550 This->stateBlock->viewport.Height);
4552 glScissor(This->stateBlock->viewport.X,
4553 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4554 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4555 This->stateBlock->viewport.Width,
4556 This->stateBlock->viewport.Height);
4558 checkGLcall("glScissor");
4560 checkGLcall("glClear");
4562 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4563 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4565 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4566 curRect[0].x2 < target->currentDesc.Width ||
4567 curRect[0].y2 < target->currentDesc.Height) {
4568 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4569 blt_to_drawable(This, target);
4573 /* Now process each rect in turn */
4574 for (i = 0; i < Count; i++) {
4575 /* Note gl uses lower left, width/height */
4576 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4577 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4578 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4579 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4581 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4582 * The rectangle is not cleared, no error is returned, but further rectanlges are
4583 * still cleared if they are valid
4585 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4586 TRACE("Rectangle with negative dimensions, ignoring\n");
4590 if(This->render_offscreen) {
4591 glScissor(curRect[i].x1, curRect[i].y1,
4592 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4594 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4595 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4597 checkGLcall("glScissor");
4600 checkGLcall("glClear");
4604 /* Restore the old values (why..?) */
4605 if (Flags & WINED3DCLEAR_STENCIL) {
4606 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4608 if (Flags & WINED3DCLEAR_TARGET) {
4609 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4610 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4611 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4612 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4613 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4618 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4619 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4621 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4622 target->Flags |= SFLAG_INTEXTURE;
4623 target->Flags &= ~SFLAG_INSYSMEM;
4625 target->Flags |= SFLAG_INDRAWABLE;
4626 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4634 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4635 UINT PrimitiveCount) {
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4639 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4640 debug_d3dprimitivetype(PrimitiveType),
4641 StartVertex, PrimitiveCount);
4643 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4644 if(This->stateBlock->streamIsUP) {
4645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4646 This->stateBlock->streamIsUP = FALSE;
4649 if(This->stateBlock->loadBaseVertexIndex != 0) {
4650 This->stateBlock->loadBaseVertexIndex = 0;
4651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4653 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4654 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4655 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4659 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4660 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4661 WINED3DPRIMITIVETYPE PrimitiveType,
4662 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 IWineD3DIndexBuffer *pIB;
4667 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4670 pIB = This->stateBlock->pIndexData;
4672 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4673 * without an index buffer set. (The first time at least...)
4674 * D3D8 simply dies, but I doubt it can do much harm to return
4675 * D3DERR_INVALIDCALL there as well. */
4676 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4677 return WINED3DERR_INVALIDCALL;
4680 if(This->stateBlock->streamIsUP) {
4681 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4682 This->stateBlock->streamIsUP = FALSE;
4684 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4686 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4687 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4688 minIndex, NumVertices, startIndex, primCount);
4690 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4691 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4697 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4698 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4702 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4703 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4708 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4709 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4710 UINT VertexStreamZeroStride) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4714 debug_d3dprimitivetype(PrimitiveType),
4715 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4717 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4718 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4719 This->stateBlock->streamOffset[0] = 0;
4720 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4721 This->stateBlock->streamIsUP = TRUE;
4722 This->stateBlock->loadBaseVertexIndex = 0;
4724 /* TODO: Only mark dirty if drawing from a different UP address */
4725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4727 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4728 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4730 /* MSDN specifies stream zero settings must be set to NULL */
4731 This->stateBlock->streamStride[0] = 0;
4732 This->stateBlock->streamSource[0] = NULL;
4734 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4735 * the new stream sources or use UP drawing again
4740 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4741 UINT MinVertexIndex, UINT NumVertices,
4742 UINT PrimitiveCount, CONST void* pIndexData,
4743 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4744 UINT VertexStreamZeroStride) {
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4748 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4749 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4750 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4751 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4753 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4759 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4760 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4761 This->stateBlock->streamIsUP = TRUE;
4762 This->stateBlock->streamOffset[0] = 0;
4763 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4765 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4766 This->stateBlock->baseVertexIndex = 0;
4767 This->stateBlock->loadBaseVertexIndex = 0;
4768 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4772 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4774 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4775 This->stateBlock->streamSource[0] = NULL;
4776 This->stateBlock->streamStride[0] = 0;
4777 This->stateBlock->pIndexData = NULL;
4778 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4779 * SetStreamSource to specify a vertex buffer
4785 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4788 /* Mark the state dirty until we have nicer tracking
4789 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4792 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4794 This->stateBlock->baseVertexIndex = 0;
4795 This->up_strided = DrawPrimStrideData;
4796 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4797 This->up_strided = NULL;
4801 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4803 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4805 /* Mark the state dirty until we have nicer tracking
4806 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4811 This->stateBlock->streamIsUP = TRUE;
4812 This->stateBlock->baseVertexIndex = 0;
4813 This->up_strided = DrawPrimStrideData;
4814 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4815 This->up_strided = NULL;
4820 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4821 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4823 HRESULT hr = WINED3D_OK;
4824 WINED3DRESOURCETYPE sourceType;
4825 WINED3DRESOURCETYPE destinationType;
4828 /* TODO: think about moving the code into IWineD3DBaseTexture */
4830 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4832 /* verify that the source and destination textures aren't NULL */
4833 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4834 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4835 This, pSourceTexture, pDestinationTexture);
4836 hr = WINED3DERR_INVALIDCALL;
4839 if (pSourceTexture == pDestinationTexture) {
4840 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4841 This, pSourceTexture, pDestinationTexture);
4842 hr = WINED3DERR_INVALIDCALL;
4844 /* Verify that the source and destination textures are the same type */
4845 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4846 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4848 if (sourceType != destinationType) {
4849 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4851 hr = WINED3DERR_INVALIDCALL;
4854 /* check that both textures have the identical numbers of levels */
4855 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4856 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4857 hr = WINED3DERR_INVALIDCALL;
4860 if (WINED3D_OK == hr) {
4862 /* Make sure that the destination texture is loaded */
4863 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4865 /* Update every surface level of the texture */
4866 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4868 switch (sourceType) {
4869 case WINED3DRTYPE_TEXTURE:
4871 IWineD3DSurface *srcSurface;
4872 IWineD3DSurface *destSurface;
4874 for (i = 0 ; i < levels ; ++i) {
4875 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4876 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4877 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4878 IWineD3DSurface_Release(srcSurface);
4879 IWineD3DSurface_Release(destSurface);
4880 if (WINED3D_OK != hr) {
4881 WARN("(%p) : Call to update surface failed\n", This);
4887 case WINED3DRTYPE_CUBETEXTURE:
4889 IWineD3DSurface *srcSurface;
4890 IWineD3DSurface *destSurface;
4891 WINED3DCUBEMAP_FACES faceType;
4893 for (i = 0 ; i < levels ; ++i) {
4894 /* Update each cube face */
4895 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4896 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4897 if (WINED3D_OK != hr) {
4898 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4900 TRACE("Got srcSurface %p\n", srcSurface);
4902 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4903 if (WINED3D_OK != hr) {
4904 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4906 TRACE("Got desrSurface %p\n", destSurface);
4908 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4909 IWineD3DSurface_Release(srcSurface);
4910 IWineD3DSurface_Release(destSurface);
4911 if (WINED3D_OK != hr) {
4912 WARN("(%p) : Call to update surface failed\n", This);
4919 #if 0 /* TODO: Add support for volume textures */
4920 case WINED3DRTYPE_VOLUMETEXTURE:
4922 IWineD3DVolume srcVolume = NULL;
4923 IWineD3DSurface destVolume = NULL;
4925 for (i = 0 ; i < levels ; ++i) {
4926 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4927 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4928 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4929 IWineD3DVolume_Release(srcSurface);
4930 IWineD3DVolume_Release(destSurface);
4931 if (WINED3D_OK != hr) {
4932 WARN("(%p) : Call to update volume failed\n", This);
4940 FIXME("(%p) : Unsupported source and destination type\n", This);
4941 hr = WINED3DERR_INVALIDCALL;
4948 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4949 IWineD3DSwapChain *swapChain;
4951 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4952 if(hr == WINED3D_OK) {
4953 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4954 IWineD3DSwapChain_Release(swapChain);
4959 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 /* return a sensible default */
4963 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4964 FIXME("(%p) : stub\n", This);
4968 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4971 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4972 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4973 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4974 return WINED3DERR_INVALIDCALL;
4976 for (j = 0; j < 256; ++j) {
4977 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4978 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4979 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4980 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4982 TRACE("(%p) : returning\n", This);
4986 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4989 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4990 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4991 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4992 return WINED3DERR_INVALIDCALL;
4994 for (j = 0; j < 256; ++j) {
4995 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4996 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4997 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4998 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5000 TRACE("(%p) : returning\n", This);
5004 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5006 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5007 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5008 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5009 return WINED3DERR_INVALIDCALL;
5011 /*TODO: stateblocks */
5012 This->currentPalette = PaletteNumber;
5013 TRACE("(%p) : returning\n", This);
5017 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5019 if (PaletteNumber == NULL) {
5020 WARN("(%p) : returning Invalid Call\n", This);
5021 return WINED3DERR_INVALIDCALL;
5023 /*TODO: stateblocks */
5024 *PaletteNumber = This->currentPalette;
5025 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5029 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5031 static BOOL showFixmes = TRUE;
5033 FIXME("(%p) : stub\n", This);
5037 This->softwareVertexProcessing = bSoftware;
5042 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5044 static BOOL showFixmes = TRUE;
5046 FIXME("(%p) : stub\n", This);
5049 return This->softwareVertexProcessing;
5053 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5055 IWineD3DSwapChain *swapChain;
5058 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5060 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5061 if(hr == WINED3D_OK){
5062 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5063 IWineD3DSwapChain_Release(swapChain);
5065 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5071 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5073 static BOOL showfixmes = TRUE;
5074 if(nSegments != 0.0f) {
5076 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5083 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5085 static BOOL showfixmes = TRUE;
5087 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5093 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5095 /** TODO: remove casts to IWineD3DSurfaceImpl
5096 * NOTE: move code to surface to accomplish this
5097 ****************************************/
5098 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5099 int srcWidth, srcHeight;
5100 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5101 WINED3DFORMAT destFormat, srcFormat;
5103 int srcLeft, destLeft, destTop;
5104 WINED3DPOOL srcPool, destPool;
5106 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5107 glDescriptor *glDescription = NULL;
5109 WINED3DSURFACE_DESC winedesc;
5111 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5112 memset(&winedesc, 0, sizeof(winedesc));
5113 winedesc.Width = &srcSurfaceWidth;
5114 winedesc.Height = &srcSurfaceHeight;
5115 winedesc.Pool = &srcPool;
5116 winedesc.Format = &srcFormat;
5118 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5120 winedesc.Width = &destSurfaceWidth;
5121 winedesc.Height = &destSurfaceHeight;
5122 winedesc.Pool = &destPool;
5123 winedesc.Format = &destFormat;
5124 winedesc.Size = &destSize;
5126 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5128 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5129 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5130 return WINED3DERR_INVALIDCALL;
5133 if (destFormat == WINED3DFMT_UNKNOWN) {
5134 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5135 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5137 /* Get the update surface description */
5138 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5141 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5145 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5146 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5147 checkGLcall("glActiveTextureARB");
5150 /* Make sure the surface is loaded and up to date */
5151 IWineD3DSurface_PreLoad(pDestinationSurface);
5153 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5155 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5156 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5157 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5158 srcLeft = pSourceRect ? pSourceRect->left : 0;
5159 destLeft = pDestPoint ? pDestPoint->x : 0;
5160 destTop = pDestPoint ? pDestPoint->y : 0;
5163 /* This function doesn't support compressed textures
5164 the pitch is just bytesPerPixel * width */
5165 if(srcWidth != srcSurfaceWidth || srcLeft ){
5166 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5167 offset += srcLeft * pSrcSurface->bytesPerPixel;
5168 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5170 /* TODO DXT formats */
5172 if(pSourceRect != NULL && pSourceRect->top != 0){
5173 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5175 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5177 ,glDescription->level
5182 ,glDescription->glFormat
5183 ,glDescription->glType
5184 ,IWineD3DSurface_GetData(pSourceSurface)
5188 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5190 /* need to lock the surface to get the data */
5191 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5194 /* TODO: Cube and volume support */
5196 /* not a whole row so we have to do it a line at a time */
5199 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5200 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5202 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5204 glTexSubImage2D(glDescription->target
5205 ,glDescription->level
5210 ,glDescription->glFormat
5211 ,glDescription->glType
5212 ,data /* could be quicker using */
5217 } else { /* Full width, so just write out the whole texture */
5219 if (WINED3DFMT_DXT1 == destFormat ||
5220 WINED3DFMT_DXT2 == destFormat ||
5221 WINED3DFMT_DXT3 == destFormat ||
5222 WINED3DFMT_DXT4 == destFormat ||
5223 WINED3DFMT_DXT5 == destFormat) {
5224 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5225 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5226 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5227 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5228 } if (destFormat != srcFormat) {
5229 FIXME("Updating mixed format compressed texture is not curretly support\n");
5231 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5232 glDescription->level,
5233 glDescription->glFormatInternal,
5238 IWineD3DSurface_GetData(pSourceSurface));
5241 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5246 glTexSubImage2D(glDescription->target
5247 ,glDescription->level
5252 ,glDescription->glFormat
5253 ,glDescription->glType
5254 ,IWineD3DSurface_GetData(pSourceSurface)
5258 checkGLcall("glTexSubImage2D");
5262 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5263 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5269 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 struct WineD3DRectPatch *patch;
5275 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5277 if(!(Handle || pRectPatchInfo)) {
5278 /* TODO: Write a test for the return value, thus the FIXME */
5279 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5280 return WINED3DERR_INVALIDCALL;
5284 i = PATCHMAP_HASHFUNC(Handle);
5286 LIST_FOR_EACH(e, &This->patches[i]) {
5287 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5288 if(patch->Handle == Handle) {
5295 TRACE("Patch does not exist. Creating a new one\n");
5296 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5297 patch->Handle = Handle;
5298 list_add_head(&This->patches[i], &patch->entry);
5300 TRACE("Found existing patch %p\n", patch);
5303 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5304 * attributes we have to tesselate, read back, and draw. This needs a patch
5305 * management structure instance. Create one.
5307 * A possible improvement is to check if a vertex shader is used, and if not directly
5310 FIXME("Drawing an uncached patch. This is slow\n");
5311 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5314 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5315 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5316 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5318 TRACE("Tesselation density or patch info changed, retesselating\n");
5320 if(pRectPatchInfo) {
5321 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5323 patch->numSegs[0] = pNumSegs[0];
5324 patch->numSegs[1] = pNumSegs[1];
5325 patch->numSegs[2] = pNumSegs[2];
5326 patch->numSegs[3] = pNumSegs[3];
5328 hr = tesselate_rectpatch(This, patch);
5330 WARN("Patch tesselation failed\n");
5332 /* Do not release the handle to store the params of the patch */
5334 HeapFree(GetProcessHeap(), 0, patch);
5340 This->currentPatch = patch;
5341 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5342 This->currentPatch = NULL;
5344 /* Destroy uncached patches */
5346 HeapFree(GetProcessHeap(), 0, patch->mem);
5347 HeapFree(GetProcessHeap(), 0, patch);
5352 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5353 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5355 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5356 FIXME("(%p) : Stub\n", This);
5360 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5363 struct WineD3DRectPatch *patch;
5365 TRACE("(%p) Handle(%d)\n", This, Handle);
5367 i = PATCHMAP_HASHFUNC(Handle);
5368 LIST_FOR_EACH(e, &This->patches[i]) {
5369 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5370 if(patch->Handle == Handle) {
5371 TRACE("Deleting patch %p\n", patch);
5372 list_remove(&patch->entry);
5373 HeapFree(GetProcessHeap(), 0, patch->mem);
5374 HeapFree(GetProcessHeap(), 0, patch);
5379 /* TODO: Write a test for the return value */
5380 FIXME("Attempt to destroy nonexistant patch\n");
5381 return WINED3DERR_INVALIDCALL;
5384 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5386 IWineD3DSwapChain *swapchain;
5388 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5389 if (SUCCEEDED(hr)) {
5390 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5397 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5401 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5402 checkGLcall("glGenFramebuffersEXT()");
5404 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5405 checkGLcall("glBindFramebuffer()");
5408 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5409 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5410 IWineD3DBaseTextureImpl *texture_impl;
5411 GLenum texttarget, target;
5414 texttarget = surface_impl->glDescription.target;
5415 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5416 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5418 IWineD3DSurface_PreLoad(surface);
5420 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5421 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5422 glBindTexture(target, old_binding);
5424 /* Update base texture states array */
5425 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5426 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5427 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5428 if (texture_impl->baseTexture.bindCount) {
5429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5432 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5435 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5437 checkGLcall("attach_surface_fbo");
5440 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5442 IWineD3DSwapChain *swapchain;
5444 swapchain = get_swapchain(surface);
5448 TRACE("Surface %p is onscreen\n", surface);
5450 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5451 buffer = surface_get_gl_buffer(surface, swapchain);
5452 glDrawBuffer(buffer);
5453 checkGLcall("glDrawBuffer()");
5455 TRACE("Surface %p is offscreen\n", surface);
5456 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5457 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5461 glEnable(GL_SCISSOR_TEST);
5463 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5465 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5466 rect->x2 - rect->x1, rect->y2 - rect->y1);
5468 checkGLcall("glScissor");
5470 glDisable(GL_SCISSOR_TEST);
5472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5474 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5477 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5478 glClear(GL_COLOR_BUFFER_BIT);
5479 checkGLcall("glClear");
5481 if (This->render_offscreen) {
5482 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5484 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5485 checkGLcall("glBindFramebuffer()");
5488 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5489 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5490 glDrawBuffer(GL_BACK);
5491 checkGLcall("glDrawBuffer()");
5495 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5497 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5499 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5501 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5502 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5503 return WINED3DERR_INVALIDCALL;
5506 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5507 color_fill_fbo(iface, pSurface, pRect, color);
5510 /* Just forward this to the DirectDraw blitting engine */
5511 memset(&BltFx, 0, sizeof(BltFx));
5512 BltFx.dwSize = sizeof(BltFx);
5513 BltFx.u5.dwFillColor = color;
5514 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5518 /* rendertarget and deptth stencil functions */
5519 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5522 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5523 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5524 return WINED3DERR_INVALIDCALL;
5527 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5528 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5529 /* Note inc ref on returned surface */
5530 if(*ppRenderTarget != NULL)
5531 IWineD3DSurface_AddRef(*ppRenderTarget);
5535 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5537 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5538 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5539 IWineD3DSwapChainImpl *Swapchain;
5542 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5544 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5545 if(hr != WINED3D_OK) {
5546 ERR("Can't get the swapchain\n");
5550 /* Make sure to release the swapchain */
5551 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5553 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5554 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5555 return WINED3DERR_INVALIDCALL;
5557 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5558 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5559 return WINED3DERR_INVALIDCALL;
5562 if(Swapchain->frontBuffer != Front) {
5563 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5565 if(Swapchain->frontBuffer)
5566 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5567 Swapchain->frontBuffer = Front;
5569 if(Swapchain->frontBuffer) {
5570 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5574 if(Back && !Swapchain->backBuffer) {
5575 /* We need memory for the back buffer array - only one back buffer this way */
5576 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5577 if(!Swapchain->backBuffer) {
5578 ERR("Out of memory\n");
5579 return E_OUTOFMEMORY;
5583 if(Swapchain->backBuffer[0] != Back) {
5584 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5586 /* What to do about the context here in the case of multithreading? Not sure.
5587 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5590 if(!Swapchain->backBuffer[0]) {
5591 /* GL was told to draw to the front buffer at creation,
5594 glDrawBuffer(GL_BACK);
5595 checkGLcall("glDrawBuffer(GL_BACK)");
5596 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5597 Swapchain->presentParms.BackBufferCount = 1;
5599 /* That makes problems - disable for now */
5600 /* glDrawBuffer(GL_FRONT); */
5601 checkGLcall("glDrawBuffer(GL_FRONT)");
5602 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5603 Swapchain->presentParms.BackBufferCount = 0;
5607 if(Swapchain->backBuffer[0])
5608 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5609 Swapchain->backBuffer[0] = Back;
5611 if(Swapchain->backBuffer[0]) {
5612 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5614 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5622 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5624 *ppZStencilSurface = This->depthStencilBuffer;
5625 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5627 if(*ppZStencilSurface != NULL) {
5628 /* Note inc ref on returned surface */
5629 IWineD3DSurface_AddRef(*ppZStencilSurface);
5634 /* TODO: Handle stencil attachments */
5635 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5637 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5639 TRACE("Set depth stencil to %p\n", depth_stencil);
5641 if (depth_stencil_impl) {
5642 if (depth_stencil_impl->current_renderbuffer) {
5643 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5644 checkGLcall("glFramebufferRenderbufferEXT()");
5646 IWineD3DBaseTextureImpl *texture_impl;
5647 GLenum texttarget, target;
5648 GLint old_binding = 0;
5650 texttarget = depth_stencil_impl->glDescription.target;
5651 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5652 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5654 IWineD3DSurface_PreLoad(depth_stencil);
5656 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5657 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5658 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5659 glBindTexture(target, old_binding);
5661 /* Update base texture states array */
5662 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5663 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5664 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5665 if (texture_impl->baseTexture.bindCount) {
5666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5669 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5672 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5673 checkGLcall("glFramebufferTexture2DEXT()");
5676 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5677 checkGLcall("glFramebufferTexture2DEXT()");
5681 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5683 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5685 TRACE("Set render target %u to %p\n", idx, render_target);
5688 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5689 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5691 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5692 checkGLcall("glFramebufferTexture2DEXT()");
5694 This->draw_buffers[idx] = GL_NONE;
5698 static void check_fbo_status(IWineD3DDevice *iface) {
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5702 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5703 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5704 TRACE("FBO complete\n");
5706 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5708 /* Dump the FBO attachments */
5709 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5710 IWineD3DSurfaceImpl *attachment;
5713 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5714 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5716 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5717 attachment->pow2Width, attachment->pow2Height);
5720 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5722 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5723 attachment->pow2Width, attachment->pow2Height);
5729 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5731 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5732 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5734 if (!ds_impl) return FALSE;
5736 if (ds_impl->current_renderbuffer) {
5737 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5738 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5741 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5742 rt_impl->pow2Height != ds_impl->pow2Height);
5745 void apply_fbo_state(IWineD3DDevice *iface) {
5746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5749 if (This->render_offscreen) {
5750 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5752 /* Apply render targets */
5753 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5754 IWineD3DSurface *render_target = This->render_targets[i];
5755 if (This->fbo_color_attachments[i] != render_target) {
5756 set_render_target_fbo(iface, i, render_target);
5757 This->fbo_color_attachments[i] = render_target;
5761 /* Apply depth targets */
5762 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5763 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5764 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5766 if (This->stencilBufferTarget) {
5767 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5769 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5770 This->fbo_depth_attachment = This->stencilBufferTarget;
5773 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5774 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5775 checkGLcall("glDrawBuffers()");
5777 glDrawBuffer(This->draw_buffers[0]);
5778 checkGLcall("glDrawBuffer()");
5781 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5784 check_fbo_status(iface);
5787 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5788 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5790 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5791 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5794 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5795 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5796 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5797 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5800 case WINED3DTEXF_LINEAR:
5801 gl_filter = GL_LINEAR;
5805 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5806 case WINED3DTEXF_NONE:
5807 case WINED3DTEXF_POINT:
5808 gl_filter = GL_NEAREST;
5812 /* Attach src surface to src fbo */
5813 src_swapchain = get_swapchain(src_surface);
5814 if (src_swapchain) {
5817 TRACE("Source surface %p is onscreen\n", src_surface);
5818 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5821 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5822 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5823 glReadBuffer(buffer);
5824 checkGLcall("glReadBuffer()");
5826 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5827 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5829 TRACE("Source surface %p is offscreen\n", src_surface);
5831 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5832 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5833 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5834 checkGLcall("glReadBuffer()");
5838 /* Attach dst surface to dst fbo */
5839 dst_swapchain = get_swapchain(dst_surface);
5840 if (dst_swapchain) {
5843 TRACE("Destination surface %p is onscreen\n", dst_surface);
5844 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5847 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5848 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5849 glDrawBuffer(buffer);
5850 checkGLcall("glDrawBuffer()");
5852 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5853 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5855 TRACE("Destination surface %p is offscreen\n", dst_surface);
5857 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5858 if(!src_swapchain) {
5859 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5863 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5864 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5865 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5866 checkGLcall("glDrawBuffer()");
5868 glDisable(GL_SCISSOR_TEST);
5869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5872 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5873 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5874 checkGLcall("glBlitFramebuffer()");
5876 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5877 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5878 checkGLcall("glBlitFramebuffer()");
5881 if (This->render_offscreen) {
5882 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5884 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5885 checkGLcall("glBindFramebuffer()");
5888 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5889 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5890 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5891 glDrawBuffer(GL_BACK);
5892 checkGLcall("glDrawBuffer()");
5897 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 WINED3DVIEWPORT viewport;
5901 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5903 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5904 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5905 return WINED3DERR_INVALIDCALL;
5908 /* MSDN says that null disables the render target
5909 but a device must always be associated with a render target
5910 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5912 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5915 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5916 FIXME("Trying to set render target 0 to NULL\n");
5917 return WINED3DERR_INVALIDCALL;
5919 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5920 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);
5921 return WINED3DERR_INVALIDCALL;
5924 /* If we are trying to set what we already have, don't bother */
5925 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5926 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5929 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5930 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5931 This->render_targets[RenderTargetIndex] = pRenderTarget;
5933 /* Render target 0 is special */
5934 if(RenderTargetIndex == 0) {
5935 /* Finally, reset the viewport as the MSDN states. */
5936 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5937 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5940 viewport.MaxZ = 1.0f;
5941 viewport.MinZ = 0.0f;
5942 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5943 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5944 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5946 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5948 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5950 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5951 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5953 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5958 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5960 HRESULT hr = WINED3D_OK;
5961 IWineD3DSurface *tmp;
5963 TRACE("(%p) Swapping z-buffer\n",This);
5965 if (pNewZStencil == This->stencilBufferTarget) {
5966 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5968 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5969 * depending on the renter target implementation being used.
5970 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5971 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5972 * stencil buffer and incure an extra memory overhead
5973 ******************************************************/
5975 tmp = This->stencilBufferTarget;
5976 This->stencilBufferTarget = pNewZStencil;
5977 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5978 /* should we be calling the parent or the wined3d surface? */
5979 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5980 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5983 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5984 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5985 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5994 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5995 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5997 /* TODO: the use of Impl is deprecated. */
5998 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5999 WINED3DLOCKED_RECT lockedRect;
6001 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6003 /* some basic validation checks */
6004 if(This->cursorTexture) {
6005 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6007 glDeleteTextures(1, &This->cursorTexture);
6009 This->cursorTexture = 0;
6012 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6013 This->haveHardwareCursor = TRUE;
6015 This->haveHardwareCursor = FALSE;
6018 WINED3DLOCKED_RECT rect;
6020 /* MSDN: Cursor must be A8R8G8B8 */
6021 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6022 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6023 return WINED3DERR_INVALIDCALL;
6026 /* MSDN: Cursor must be smaller than the display mode */
6027 if(pSur->currentDesc.Width > This->ddraw_width ||
6028 pSur->currentDesc.Height > This->ddraw_height) {
6029 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);
6030 return WINED3DERR_INVALIDCALL;
6033 if (!This->haveHardwareCursor) {
6034 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6036 /* Do not store the surface's pointer because the application may
6037 * release it after setting the cursor image. Windows doesn't
6038 * addref the set surface, so we can't do this either without
6039 * creating circular refcount dependencies. Copy out the gl texture
6042 This->cursorWidth = pSur->currentDesc.Width;
6043 This->cursorHeight = pSur->currentDesc.Height;
6044 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6046 const GlPixelFormatDesc *glDesc;
6047 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6048 char *mem, *bits = (char *)rect.pBits;
6049 GLint intfmt = glDesc->glInternal;
6050 GLint format = glDesc->glFormat;
6051 GLint type = glDesc->glType;
6052 INT height = This->cursorHeight;
6053 INT width = This->cursorWidth;
6054 INT bpp = tableEntry->bpp;
6057 /* Reformat the texture memory (pitch and width can be
6059 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6060 for(i = 0; i < height; i++)
6061 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6062 IWineD3DSurface_UnlockRect(pCursorBitmap);
6065 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6066 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6067 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6070 /* Make sure that a proper texture unit is selected */
6071 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6072 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6073 checkGLcall("glActiveTextureARB");
6075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6076 /* Create a new cursor texture */
6077 glGenTextures(1, &This->cursorTexture);
6078 checkGLcall("glGenTextures");
6079 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6080 checkGLcall("glBindTexture");
6081 /* Copy the bitmap memory into the cursor texture */
6082 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6083 HeapFree(GetProcessHeap(), 0, mem);
6084 checkGLcall("glTexImage2D");
6086 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6087 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6088 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6095 FIXME("A cursor texture was not returned.\n");
6096 This->cursorTexture = 0;
6101 /* Draw a hardware cursor */
6102 ICONINFO cursorInfo;
6104 /* Create and clear maskBits because it is not needed for
6105 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6107 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6108 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6109 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6110 WINED3DLOCK_NO_DIRTY_UPDATE |
6111 WINED3DLOCK_READONLY
6113 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6114 pSur->currentDesc.Height);
6116 cursorInfo.fIcon = FALSE;
6117 cursorInfo.xHotspot = XHotSpot;
6118 cursorInfo.yHotspot = YHotSpot;
6119 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6120 pSur->currentDesc.Height, 1,
6122 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6123 pSur->currentDesc.Height, 1,
6124 32, lockedRect.pBits);
6125 IWineD3DSurface_UnlockRect(pCursorBitmap);
6126 /* Create our cursor and clean up. */
6127 cursor = CreateIconIndirect(&cursorInfo);
6129 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6130 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6131 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6132 This->hardwareCursor = cursor;
6133 HeapFree(GetProcessHeap(), 0, maskBits);
6137 This->xHotSpot = XHotSpot;
6138 This->yHotSpot = YHotSpot;
6142 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6144 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6146 This->xScreenSpace = XScreenSpace;
6147 This->yScreenSpace = YScreenSpace;
6153 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6155 BOOL oldVisible = This->bCursorVisible;
6158 TRACE("(%p) : visible(%d)\n", This, bShow);
6161 * When ShowCursor is first called it should make the cursor appear at the OS's last
6162 * known cursor position. Because of this, some applications just repetitively call
6163 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6166 This->xScreenSpace = pt.x;
6167 This->yScreenSpace = pt.y;
6169 if (This->haveHardwareCursor) {
6170 This->bCursorVisible = bShow;
6172 SetCursor(This->hardwareCursor);
6178 if (This->cursorTexture)
6179 This->bCursorVisible = bShow;
6185 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6187 TRACE("(%p) : state (%u)\n", This, This->state);
6188 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6189 switch (This->state) {
6192 case WINED3DERR_DEVICELOST:
6194 ResourceList *resourceList = This->resources;
6195 while (NULL != resourceList) {
6196 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6197 return WINED3DERR_DEVICENOTRESET;
6198 resourceList = resourceList->next;
6200 return WINED3DERR_DEVICELOST;
6202 case WINED3DERR_DRIVERINTERNALERROR:
6203 return WINED3DERR_DRIVERINTERNALERROR;
6207 return WINED3DERR_DRIVERINTERNALERROR;
6211 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6213 /** FIXME: Resource tracking needs to be done,
6214 * The closes we can do to this is set the priorities of all managed textures low
6215 * and then reset them.
6216 ***********************************************************/
6217 FIXME("(%p) : stub\n", This);
6221 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6222 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6224 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6225 if(surface->Flags & SFLAG_DIBSECTION) {
6226 /* Release the DC */
6227 SelectObject(surface->hDC, surface->dib.holdbitmap);
6228 DeleteDC(surface->hDC);
6229 /* Release the DIB section */
6230 DeleteObject(surface->dib.DIBsection);
6231 surface->dib.bitmap_data = NULL;
6232 surface->resource.allocatedMemory = NULL;
6233 surface->Flags &= ~SFLAG_DIBSECTION;
6235 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6236 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6237 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6238 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6239 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6241 surface->pow2Width = surface->pow2Height = 1;
6242 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6243 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6245 if(surface->glDescription.textureName) {
6246 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6248 glDeleteTextures(1, &surface->glDescription.textureName);
6250 surface->glDescription.textureName = 0;
6251 surface->Flags &= ~SFLAG_CLIENT;
6253 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6254 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6255 surface->Flags |= SFLAG_NONPOW2;
6257 surface->Flags &= ~SFLAG_NONPOW2;
6259 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6260 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6263 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6265 IWineD3DSwapChainImpl *swapchain;
6267 BOOL DisplayModeChanged = FALSE;
6268 WINED3DDISPLAYMODE mode;
6269 TRACE("(%p)\n", This);
6271 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6273 ERR("Failed to get the first implicit swapchain\n");
6277 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6278 * on an existing gl context, so there's no real need for recreation.
6280 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6282 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6284 TRACE("New params:\n");
6285 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6286 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6287 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6288 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6289 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6290 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6291 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6292 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6293 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6294 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6295 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6296 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6297 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6299 /* No special treatment of these parameters. Just store them */
6300 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6301 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6302 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6303 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6305 /* What to do about these? */
6306 if(pPresentationParameters->BackBufferCount != 0 &&
6307 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6308 ERR("Cannot change the back buffer count yet\n");
6310 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6311 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6312 ERR("Cannot change the back buffer format yet\n");
6314 if(pPresentationParameters->hDeviceWindow != NULL &&
6315 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6316 ERR("Cannot change the device window yet\n");
6318 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6319 ERR("What do do about a changed auto depth stencil parameter?\n");
6322 if(pPresentationParameters->Windowed) {
6323 mode.Width = swapchain->orig_width;
6324 mode.Height = swapchain->orig_height;
6325 mode.RefreshRate = 0;
6326 mode.Format = swapchain->presentParms.BackBufferFormat;
6328 mode.Width = pPresentationParameters->BackBufferWidth;
6329 mode.Height = pPresentationParameters->BackBufferHeight;
6330 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6331 mode.Format = swapchain->presentParms.BackBufferFormat;
6334 /* Should Width == 800 && Height == 0 set 800x600? */
6335 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6336 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6337 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6344 vp.Width = pPresentationParameters->BackBufferWidth;
6345 vp.Height = pPresentationParameters->BackBufferHeight;
6349 if(!pPresentationParameters->Windowed) {
6350 DisplayModeChanged = TRUE;
6352 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6353 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6355 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6356 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6357 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6360 /* Now set the new viewport */
6361 IWineD3DDevice_SetViewport(iface, &vp);
6364 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6365 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6366 DisplayModeChanged) {
6368 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6369 if(!pPresentationParameters->Windowed) {
6370 IWineD3DDevice_SetFullscreen(iface, TRUE);
6373 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6375 /* Switching out of fullscreen mode? First set the original res, then change the window */
6376 if(pPresentationParameters->Windowed) {
6377 IWineD3DDevice_SetFullscreen(iface, FALSE);
6379 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6382 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6386 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6388 /** FIXME: always true at the moment **/
6389 if(!bEnableDialogs) {
6390 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6396 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6398 TRACE("(%p) : pParameters %p\n", This, pParameters);
6400 *pParameters = This->createParms;
6404 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6405 IWineD3DSwapChain *swapchain;
6406 HRESULT hrc = WINED3D_OK;
6408 TRACE("Relaying to swapchain\n");
6410 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6411 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6412 IWineD3DSwapChain_Release(swapchain);
6417 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6418 IWineD3DSwapChain *swapchain;
6419 HRESULT hrc = WINED3D_OK;
6421 TRACE("Relaying to swapchain\n");
6423 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6424 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6425 IWineD3DSwapChain_Release(swapchain);
6431 /** ********************************************************
6432 * Notification functions
6433 ** ********************************************************/
6434 /** This function must be called in the release of a resource when ref == 0,
6435 * the contents of resource must still be correct,
6436 * any handels to other resource held by the caller must be closed
6437 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6438 *****************************************************/
6439 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6441 ResourceList* resourceList;
6443 TRACE("(%p) : resource %p\n", This, resource);
6444 /* add a new texture to the frot of the linked list */
6445 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6446 resourceList->resource = resource;
6448 /* Get the old head */
6449 resourceList->next = This->resources;
6451 This->resources = resourceList;
6452 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6457 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6459 ResourceList* resourceList = NULL;
6460 ResourceList* previousResourceList = NULL;
6462 TRACE("(%p) : resource %p\n", This, resource);
6464 resourceList = This->resources;
6466 while (resourceList != NULL) {
6467 if(resourceList->resource == resource) break;
6468 previousResourceList = resourceList;
6469 resourceList = resourceList->next;
6472 if (resourceList == NULL) {
6473 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6476 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6478 /* make sure we don't leave a hole in the list */
6479 if (previousResourceList != NULL) {
6480 previousResourceList->next = resourceList->next;
6482 This->resources = resourceList->next;
6489 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6493 TRACE("(%p) : resource %p\n", This, resource);
6494 switch(IWineD3DResource_GetType(resource)){
6495 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6496 case WINED3DRTYPE_SURFACE: {
6499 /* Cleanup any FBO attachments if d3d is enabled */
6500 if(This->d3d_initialized) {
6501 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6502 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6503 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6504 set_render_target_fbo(iface, i, NULL);
6505 This->fbo_color_attachments[i] = NULL;
6508 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6509 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6510 set_depth_stencil_fbo(iface, NULL);
6511 This->fbo_depth_attachment = NULL;
6517 case WINED3DRTYPE_TEXTURE:
6518 case WINED3DRTYPE_CUBETEXTURE:
6519 case WINED3DRTYPE_VOLUMETEXTURE:
6520 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6521 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6522 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6523 This->stateBlock->textures[counter] = NULL;
6525 if (This->updateStateBlock != This->stateBlock ){
6526 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6527 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6528 This->updateStateBlock->textures[counter] = NULL;
6533 case WINED3DRTYPE_VOLUME:
6534 /* TODO: nothing really? */
6536 case WINED3DRTYPE_VERTEXBUFFER:
6537 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6540 TRACE("Cleaning up stream pointers\n");
6542 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6543 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6544 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6546 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6547 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6548 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6549 This->updateStateBlock->streamSource[streamNumber] = 0;
6550 /* Set changed flag? */
6553 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) */
6554 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6555 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6556 This->stateBlock->streamSource[streamNumber] = 0;
6559 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6560 else { /* This shouldn't happen */
6561 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6568 case WINED3DRTYPE_INDEXBUFFER:
6569 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6570 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6571 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6572 This->updateStateBlock->pIndexData = NULL;
6575 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6576 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6577 This->stateBlock->pIndexData = NULL;
6583 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6588 /* Remove the resoruce from the resourceStore */
6589 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6591 TRACE("Resource released\n");
6595 /**********************************************************
6596 * IWineD3DDevice VTbl follows
6597 **********************************************************/
6599 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6601 /*** IUnknown methods ***/
6602 IWineD3DDeviceImpl_QueryInterface,
6603 IWineD3DDeviceImpl_AddRef,
6604 IWineD3DDeviceImpl_Release,
6605 /*** IWineD3DDevice methods ***/
6606 IWineD3DDeviceImpl_GetParent,
6607 /*** Creation methods**/
6608 IWineD3DDeviceImpl_CreateVertexBuffer,
6609 IWineD3DDeviceImpl_CreateIndexBuffer,
6610 IWineD3DDeviceImpl_CreateStateBlock,
6611 IWineD3DDeviceImpl_CreateSurface,
6612 IWineD3DDeviceImpl_CreateTexture,
6613 IWineD3DDeviceImpl_CreateVolumeTexture,
6614 IWineD3DDeviceImpl_CreateVolume,
6615 IWineD3DDeviceImpl_CreateCubeTexture,
6616 IWineD3DDeviceImpl_CreateQuery,
6617 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6618 IWineD3DDeviceImpl_CreateVertexDeclaration,
6619 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6620 IWineD3DDeviceImpl_CreateVertexShader,
6621 IWineD3DDeviceImpl_CreatePixelShader,
6622 IWineD3DDeviceImpl_CreatePalette,
6623 /*** Odd functions **/
6624 IWineD3DDeviceImpl_Init3D,
6625 IWineD3DDeviceImpl_Uninit3D,
6626 IWineD3DDeviceImpl_SetFullscreen,
6627 IWineD3DDeviceImpl_SetMultithreaded,
6628 IWineD3DDeviceImpl_EvictManagedResources,
6629 IWineD3DDeviceImpl_GetAvailableTextureMem,
6630 IWineD3DDeviceImpl_GetBackBuffer,
6631 IWineD3DDeviceImpl_GetCreationParameters,
6632 IWineD3DDeviceImpl_GetDeviceCaps,
6633 IWineD3DDeviceImpl_GetDirect3D,
6634 IWineD3DDeviceImpl_GetDisplayMode,
6635 IWineD3DDeviceImpl_SetDisplayMode,
6636 IWineD3DDeviceImpl_GetHWND,
6637 IWineD3DDeviceImpl_SetHWND,
6638 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6639 IWineD3DDeviceImpl_GetRasterStatus,
6640 IWineD3DDeviceImpl_GetSwapChain,
6641 IWineD3DDeviceImpl_Reset,
6642 IWineD3DDeviceImpl_SetDialogBoxMode,
6643 IWineD3DDeviceImpl_SetCursorProperties,
6644 IWineD3DDeviceImpl_SetCursorPosition,
6645 IWineD3DDeviceImpl_ShowCursor,
6646 IWineD3DDeviceImpl_TestCooperativeLevel,
6647 /*** Getters and setters **/
6648 IWineD3DDeviceImpl_SetClipPlane,
6649 IWineD3DDeviceImpl_GetClipPlane,
6650 IWineD3DDeviceImpl_SetClipStatus,
6651 IWineD3DDeviceImpl_GetClipStatus,
6652 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6653 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6654 IWineD3DDeviceImpl_SetDepthStencilSurface,
6655 IWineD3DDeviceImpl_GetDepthStencilSurface,
6656 IWineD3DDeviceImpl_SetFVF,
6657 IWineD3DDeviceImpl_GetFVF,
6658 IWineD3DDeviceImpl_SetGammaRamp,
6659 IWineD3DDeviceImpl_GetGammaRamp,
6660 IWineD3DDeviceImpl_SetIndices,
6661 IWineD3DDeviceImpl_GetIndices,
6662 IWineD3DDeviceImpl_SetBaseVertexIndex,
6663 IWineD3DDeviceImpl_GetBaseVertexIndex,
6664 IWineD3DDeviceImpl_SetLight,
6665 IWineD3DDeviceImpl_GetLight,
6666 IWineD3DDeviceImpl_SetLightEnable,
6667 IWineD3DDeviceImpl_GetLightEnable,
6668 IWineD3DDeviceImpl_SetMaterial,
6669 IWineD3DDeviceImpl_GetMaterial,
6670 IWineD3DDeviceImpl_SetNPatchMode,
6671 IWineD3DDeviceImpl_GetNPatchMode,
6672 IWineD3DDeviceImpl_SetPaletteEntries,
6673 IWineD3DDeviceImpl_GetPaletteEntries,
6674 IWineD3DDeviceImpl_SetPixelShader,
6675 IWineD3DDeviceImpl_GetPixelShader,
6676 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6677 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6678 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6679 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6680 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6681 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6682 IWineD3DDeviceImpl_SetRenderState,
6683 IWineD3DDeviceImpl_GetRenderState,
6684 IWineD3DDeviceImpl_SetRenderTarget,
6685 IWineD3DDeviceImpl_GetRenderTarget,
6686 IWineD3DDeviceImpl_SetFrontBackBuffers,
6687 IWineD3DDeviceImpl_SetSamplerState,
6688 IWineD3DDeviceImpl_GetSamplerState,
6689 IWineD3DDeviceImpl_SetScissorRect,
6690 IWineD3DDeviceImpl_GetScissorRect,
6691 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6692 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6693 IWineD3DDeviceImpl_SetStreamSource,
6694 IWineD3DDeviceImpl_GetStreamSource,
6695 IWineD3DDeviceImpl_SetStreamSourceFreq,
6696 IWineD3DDeviceImpl_GetStreamSourceFreq,
6697 IWineD3DDeviceImpl_SetTexture,
6698 IWineD3DDeviceImpl_GetTexture,
6699 IWineD3DDeviceImpl_SetTextureStageState,
6700 IWineD3DDeviceImpl_GetTextureStageState,
6701 IWineD3DDeviceImpl_SetTransform,
6702 IWineD3DDeviceImpl_GetTransform,
6703 IWineD3DDeviceImpl_SetVertexDeclaration,
6704 IWineD3DDeviceImpl_GetVertexDeclaration,
6705 IWineD3DDeviceImpl_SetVertexShader,
6706 IWineD3DDeviceImpl_GetVertexShader,
6707 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6708 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6709 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6710 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6711 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6712 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6713 IWineD3DDeviceImpl_SetViewport,
6714 IWineD3DDeviceImpl_GetViewport,
6715 IWineD3DDeviceImpl_MultiplyTransform,
6716 IWineD3DDeviceImpl_ValidateDevice,
6717 IWineD3DDeviceImpl_ProcessVertices,
6718 /*** State block ***/
6719 IWineD3DDeviceImpl_BeginStateBlock,
6720 IWineD3DDeviceImpl_EndStateBlock,
6721 /*** Scene management ***/
6722 IWineD3DDeviceImpl_BeginScene,
6723 IWineD3DDeviceImpl_EndScene,
6724 IWineD3DDeviceImpl_Present,
6725 IWineD3DDeviceImpl_Clear,
6727 IWineD3DDeviceImpl_DrawPrimitive,
6728 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6729 IWineD3DDeviceImpl_DrawPrimitiveUP,
6730 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6731 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6732 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6733 IWineD3DDeviceImpl_DrawRectPatch,
6734 IWineD3DDeviceImpl_DrawTriPatch,
6735 IWineD3DDeviceImpl_DeletePatch,
6736 IWineD3DDeviceImpl_ColorFill,
6737 IWineD3DDeviceImpl_UpdateTexture,
6738 IWineD3DDeviceImpl_UpdateSurface,
6739 IWineD3DDeviceImpl_GetFrontBufferData,
6740 /*** object tracking ***/
6741 IWineD3DDeviceImpl_ResourceReleased
6745 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6746 WINED3DRS_ALPHABLENDENABLE ,
6747 WINED3DRS_ALPHAFUNC ,
6748 WINED3DRS_ALPHAREF ,
6749 WINED3DRS_ALPHATESTENABLE ,
6751 WINED3DRS_COLORWRITEENABLE ,
6752 WINED3DRS_DESTBLEND ,
6753 WINED3DRS_DITHERENABLE ,
6754 WINED3DRS_FILLMODE ,
6755 WINED3DRS_FOGDENSITY ,
6757 WINED3DRS_FOGSTART ,
6758 WINED3DRS_LASTPIXEL ,
6759 WINED3DRS_SHADEMODE ,
6760 WINED3DRS_SRCBLEND ,
6761 WINED3DRS_STENCILENABLE ,
6762 WINED3DRS_STENCILFAIL ,
6763 WINED3DRS_STENCILFUNC ,
6764 WINED3DRS_STENCILMASK ,
6765 WINED3DRS_STENCILPASS ,
6766 WINED3DRS_STENCILREF ,
6767 WINED3DRS_STENCILWRITEMASK ,
6768 WINED3DRS_STENCILZFAIL ,
6769 WINED3DRS_TEXTUREFACTOR ,
6780 WINED3DRS_ZWRITEENABLE
6783 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6784 WINED3DTSS_ADDRESSW ,
6785 WINED3DTSS_ALPHAARG0 ,
6786 WINED3DTSS_ALPHAARG1 ,
6787 WINED3DTSS_ALPHAARG2 ,
6788 WINED3DTSS_ALPHAOP ,
6789 WINED3DTSS_BUMPENVLOFFSET ,
6790 WINED3DTSS_BUMPENVLSCALE ,
6791 WINED3DTSS_BUMPENVMAT00 ,
6792 WINED3DTSS_BUMPENVMAT01 ,
6793 WINED3DTSS_BUMPENVMAT10 ,
6794 WINED3DTSS_BUMPENVMAT11 ,
6795 WINED3DTSS_COLORARG0 ,
6796 WINED3DTSS_COLORARG1 ,
6797 WINED3DTSS_COLORARG2 ,
6798 WINED3DTSS_COLOROP ,
6799 WINED3DTSS_RESULTARG ,
6800 WINED3DTSS_TEXCOORDINDEX ,
6801 WINED3DTSS_TEXTURETRANSFORMFLAGS
6804 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6805 WINED3DSAMP_ADDRESSU ,
6806 WINED3DSAMP_ADDRESSV ,
6807 WINED3DSAMP_ADDRESSW ,
6808 WINED3DSAMP_BORDERCOLOR ,
6809 WINED3DSAMP_MAGFILTER ,
6810 WINED3DSAMP_MINFILTER ,
6811 WINED3DSAMP_MIPFILTER ,
6812 WINED3DSAMP_MIPMAPLODBIAS ,
6813 WINED3DSAMP_MAXMIPLEVEL ,
6814 WINED3DSAMP_MAXANISOTROPY ,
6815 WINED3DSAMP_SRGBTEXTURE ,
6816 WINED3DSAMP_ELEMENTINDEX
6819 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6821 WINED3DRS_AMBIENTMATERIALSOURCE ,
6822 WINED3DRS_CLIPPING ,
6823 WINED3DRS_CLIPPLANEENABLE ,
6824 WINED3DRS_COLORVERTEX ,
6825 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6826 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6827 WINED3DRS_FOGDENSITY ,
6829 WINED3DRS_FOGSTART ,
6830 WINED3DRS_FOGTABLEMODE ,
6831 WINED3DRS_FOGVERTEXMODE ,
6832 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6833 WINED3DRS_LIGHTING ,
6834 WINED3DRS_LOCALVIEWER ,
6835 WINED3DRS_MULTISAMPLEANTIALIAS ,
6836 WINED3DRS_MULTISAMPLEMASK ,
6837 WINED3DRS_NORMALIZENORMALS ,
6838 WINED3DRS_PATCHEDGESTYLE ,
6839 WINED3DRS_POINTSCALE_A ,
6840 WINED3DRS_POINTSCALE_B ,
6841 WINED3DRS_POINTSCALE_C ,
6842 WINED3DRS_POINTSCALEENABLE ,
6843 WINED3DRS_POINTSIZE ,
6844 WINED3DRS_POINTSIZE_MAX ,
6845 WINED3DRS_POINTSIZE_MIN ,
6846 WINED3DRS_POINTSPRITEENABLE ,
6847 WINED3DRS_RANGEFOGENABLE ,
6848 WINED3DRS_SPECULARMATERIALSOURCE ,
6849 WINED3DRS_TWEENFACTOR ,
6850 WINED3DRS_VERTEXBLEND
6853 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6854 WINED3DTSS_TEXCOORDINDEX ,
6855 WINED3DTSS_TEXTURETRANSFORMFLAGS
6858 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6859 WINED3DSAMP_DMAPOFFSET
6862 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6863 DWORD rep = StateTable[state].representative;
6867 WineD3DContext *context;
6870 for(i = 0; i < This->numContexts; i++) {
6871 context = This->contexts[i];
6872 if(isStateDirty(context, rep)) continue;
6874 context->dirtyArray[context->numDirtyEntries++] = rep;
6877 context->isStateDirty[idx] |= (1 << shift);