comctl32: We can now store binary files in the repository.
[wine] / dlls / wined3d / device.c
1 /*
2  * IWineD3DDevice implementation
3  *
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
12  *
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.
17  *
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.
22  *
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
26  */
27
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
37
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
40
41     WINED3DLIGHT_DIRECTIONAL, /* Type */
42     { 1.0, 1.0, 1.0, 0.0 },   /* Diffuse r,g,b,a */
43     { 0.0, 0.0, 0.0, 0.0 },   /* Specular r,g,b,a */
44     { 0.0, 0.0, 0.0, 0.0 },   /* Ambient r,g,b,a, */
45     { 0.0, 0.0, 0.0 },        /* Position x,y,z */
46     { 0.0, 0.0, 1.0 },        /* Direction x,y,z */
47     0.0,                      /* Range */
48     0.0,                      /* Falloff */
49     0.0, 0.0, 0.0,            /* Attenuation 0,1,2 */
50     0.0,                      /* Theta */
51     0.0                       /* Phi */
52 };
53
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
56
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
59
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; \
66     object->ref          = 1; \
67     *pp##type = (IWineD3D##type *) object; \
68 }
69
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; \
75     object->ref          = 1; \
76     object->baseShader.device = (IWineD3DDevice*) This; \
77     list_init(&object->baseShader.linked_programs); \
78     *pp##type = (IWineD3D##type *) object; \
79 }
80
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); \
99             *pp##type = NULL; \
100             return WINED3DERR_OUTOFVIDEOMEMORY; \
101         } \
102         globalChangeGlRam(_size); \
103     } \
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); \
108         *pp##type = NULL; \
109         return WINED3DERR_OUTOFVIDEOMEMORY; \
110     } \
111     *pp##type = (IWineD3D##type *) object; \
112     IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113     TRACE("(%p) : Created resource %p\n", This, object); \
114 }
115
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; \
123 }
124
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 */
129
130 /**********************************************************
131  * IUnknown parts follows
132  **********************************************************/
133
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
135 {
136     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
137
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);
143         *ppobj = This;
144         return S_OK;
145     }
146     *ppobj = NULL;
147     return E_NOINTERFACE;
148 }
149
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152     ULONG refCount = InterlockedIncrement(&This->ref);
153
154     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155     return refCount;
156 }
157
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160     ULONG refCount = InterlockedDecrement(&This->ref);
161
162     TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
163
164     if (!refCount) {
165         if (This->fbo) {
166             GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
167         }
168         if (This->src_fbo) {
169             GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
170         }
171         if (This->dst_fbo) {
172             GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
173         }
174
175         if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
176
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         ** ***************************/
180
181         if (This->resources != NULL ) {
182             FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183             dumpResources(This->resources);
184         }
185
186         if(This->contexts) ERR("Context array not freed!\n");
187         if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188         This->haveHardwareCursor = FALSE;
189
190         IWineD3D_Release(This->wineD3D);
191         This->wineD3D = NULL;
192         HeapFree(GetProcessHeap(), 0, This);
193         TRACE("Freed device  %p\n", This);
194         This = NULL;
195     }
196     return refCount;
197 }
198
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);
206     return WINED3D_OK;
207 }
208
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");
215         return;
216     }
217
218     TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p  Usage(%s)\n", object, debug_d3dusage(vboUsage));
219
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);
222     ENTER_GL();
223
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)
228       */
229     while(glGetError() != GL_NO_ERROR);
230
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.
236       */
237
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);
242         goto error;
243     }
244
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);
249         goto error;
250     }
251
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.
255      */
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;
261             break;
262         case WINED3DUSAGE_WRITEONLY:
263         default:
264             TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265             glUsage = GL_DYNAMIC_DRAW_ARB;
266             break;
267     }
268
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
272      */
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);
277         goto error;
278     }
279
280     LEAVE_GL();
281
282     return;
283     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));
287     object->vbo = 0;
288     object->Flags |= VBFLAG_VBOCREATEFAIL;
289     LEAVE_GL();
290     return;
291 }
292
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage, 
294                              DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295                              IUnknown *parent) {
296     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297     IWineD3DVertexBufferImpl *object;
298     WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299     int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300     BOOL conv;
301
302     if(Size == 0) {
303         WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304         *ppVertexBuffer = NULL;
305         return WINED3DERR_INVALIDCALL;
306     }
307
308     D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
309
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;
312
313     if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314         object->resource.allocatedMemory  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
315     }
316     object->fvf = FVF;
317
318     /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319      * drawStridedFast (half-life 2).
320      *
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.
324      *
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
329      * dx7 apps.
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.
332      */
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) ) {
336         CreateVBO(object);
337     }
338     return WINED3D_OK;
339 }
340
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342     GLenum error, glUsage;
343     TRACE("Creating VBO for Index Buffer %p\n", object);
344
345     /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346      * restored on the next draw
347      */
348     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
349
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);
352     ENTER_GL();
353
354     while(glGetError());
355
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);
360         goto out;
361     }
362
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);
367         goto out;
368     }
369
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
372         */
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);
378         goto out;
379     }
380     LEAVE_GL();
381     TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382     return;
383
384 out:
385     GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386     GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387     LEAVE_GL();
388     object->vbo = 0;
389 }
390
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);
397
398     /* Allocate the storage for the device */
399     D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
400
401     if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402         object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
403     }
404
405     if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406         CreateIndexBufferVBO(This, object);
407     }
408
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;
412
413     return WINED3D_OK;
414 }
415
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
417
418     IWineD3DDeviceImpl     *This = (IWineD3DDeviceImpl *)iface;
419     IWineD3DStateBlockImpl *object;
420     int i, j;
421     HRESULT temp_result;
422
423     D3DCREATEOBJECTINSTANCE(object, StateBlock)
424     object->blockType     = Type;
425
426     for(i = 0; i < LIGHTMAP_SIZE; i++) {
427         list_init(&object->lightMap[i]);
428     }
429
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                                   */
435         return WINED3D_OK;
436     }
437     
438     temp_result = allocate_shader_constants(object);
439     if (WINED3D_OK != temp_result)
440         return temp_result;
441
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);
445     else
446         memset(object->streamFreq, 1, sizeof(object->streamFreq));
447
448     /* Reset the ref and type after kludging it */
449     object->wineD3DDevice = This;
450     object->ref           = 1;
451     object->blockType     = Type;
452
453     TRACE("Updating changed flags appropriate for type %d\n", Type);
454
455     if (Type == WINED3DSBT_ALL) {
456
457         TRACE("ALL => Pretend everything has changed\n");
458         stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
459
460         /* Lights are not part of the changed / set structure */
461         for(j = 0; j < LIGHTMAP_SIZE; j++) {
462             struct list *e;
463             LIST_FOR_EACH(e, &object->lightMap[j]) {
464                 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465                 light->changed = TRUE;
466                 light->enabledChanged = TRUE;
467             }
468         }
469         for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470             object->contained_render_states[j - 1] = j;
471         }
472         object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473         /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474         for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475             object->contained_transform_states[j - 1] = j;
476         }
477         object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478         for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479             object->contained_vs_consts_f[j] = j;
480         }
481         object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482         for(j = 0; j < MAX_CONST_I; j++) {
483             object->contained_vs_consts_i[j] = j;
484         }
485         object->num_contained_vs_consts_i = MAX_CONST_I;
486         for(j = 0; j < MAX_CONST_B; j++) {
487             object->contained_vs_consts_b[j] = j;
488         }
489         object->num_contained_vs_consts_b = MAX_CONST_B;
490         for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491             object->contained_ps_consts_f[j] = j;
492         }
493         object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494         for(j = 0; j < MAX_CONST_I; j++) {
495             object->contained_ps_consts_i[j] = j;
496         }
497         object->num_contained_ps_consts_i = MAX_CONST_I;
498         for(j = 0; j < MAX_CONST_B; j++) {
499             object->contained_ps_consts_b[j] = j;
500         }
501         object->num_contained_ps_consts_b = MAX_CONST_B;
502         for(i = 0; i < MAX_TEXTURES; i++) {
503             for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504                 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505                 object->contained_tss_states[object->num_contained_tss_states].state = j;
506                 object->num_contained_tss_states++;
507             }
508         }
509         for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510             for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511                 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512                 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513                 object->num_contained_sampler_states++;
514             }
515         }
516
517         for(i = 0; i < MAX_STREAMS; i++) {
518             if(object->streamSource[i]) {
519                 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
520             }
521         }
522         if(object->pIndexData) {
523             IWineD3DIndexBuffer_AddRef(object->pIndexData);
524         }
525         if(object->vertexShader) {
526             IWineD3DVertexShader_AddRef(object->vertexShader);
527         }
528         if(object->pixelShader) {
529             IWineD3DPixelShader_AddRef(object->pixelShader);
530         }
531
532     } else if (Type == WINED3DSBT_PIXELSTATE) {
533
534         TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535         stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
536
537         object->changed.pixelShader = TRUE;
538
539         /* Pixel Shader Constants */
540         for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541             object->contained_ps_consts_f[i] = i;
542             object->changed.pixelShaderConstantsF[i] = TRUE;
543         }
544         object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545         for (i = 0; i < MAX_CONST_B; ++i) {
546             object->contained_ps_consts_b[i] = i;
547             object->changed.pixelShaderConstantsB[i] = TRUE;
548         }
549         object->num_contained_ps_consts_b = MAX_CONST_B;
550         for (i = 0; i < MAX_CONST_I; ++i) {
551             object->contained_ps_consts_i[i] = i;
552             object->changed.pixelShaderConstantsI[i] = TRUE;
553         }
554         object->num_contained_ps_consts_i = MAX_CONST_I;
555
556         for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557             object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558             object->contained_render_states[i] = SavedPixelStates_R[i];
559         }
560         object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561         for (j = 0; j < MAX_TEXTURES; j++) {
562             for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563                 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564                 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565                 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566                 object->num_contained_tss_states++;
567             }
568         }
569         for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570             for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571                 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572                 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573                 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574                 object->num_contained_sampler_states++;
575             }
576         }
577         if(object->pixelShader) {
578             IWineD3DPixelShader_AddRef(object->pixelShader);
579         }
580
581         /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582          * on them. This makes releasing the buffer easier
583          */
584         for(i = 0; i < MAX_STREAMS; i++) {
585             object->streamSource[i] = NULL;
586         }
587         object->pIndexData = NULL;
588         object->vertexShader = NULL;
589
590     } else if (Type == WINED3DSBT_VERTEXSTATE) {
591
592         TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593         stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
594
595         object->changed.vertexShader = TRUE;
596
597         /* Vertex Shader Constants */
598         for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599             object->changed.vertexShaderConstantsF[i] = TRUE;
600             object->contained_vs_consts_f[i] = i;
601         }
602         object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603         for (i = 0; i < MAX_CONST_B; ++i) {
604             object->changed.vertexShaderConstantsB[i] = TRUE;
605             object->contained_vs_consts_b[i] = i;
606         }
607         object->num_contained_vs_consts_b = MAX_CONST_B;
608         for (i = 0; i < MAX_CONST_I; ++i) {
609             object->changed.vertexShaderConstantsI[i] = TRUE;
610             object->contained_vs_consts_i[i] = i;
611         }
612         object->num_contained_vs_consts_i = MAX_CONST_I;
613         for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614             object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615             object->contained_render_states[i] = SavedVertexStates_R[i];
616         }
617         object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618         for (j = 0; j < MAX_TEXTURES; j++) {
619             for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620                 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621                 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622                 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623                 object->num_contained_tss_states++;
624             }
625         }
626         for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627             for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628                 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629                 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630                 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631                 object->num_contained_sampler_states++;
632             }
633         }
634
635         for(j = 0; j < LIGHTMAP_SIZE; j++) {
636             struct list *e;
637             LIST_FOR_EACH(e, &object->lightMap[j]) {
638                 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639                 light->changed = TRUE;
640                 light->enabledChanged = TRUE;
641             }
642         }
643
644         for(i = 0; i < MAX_STREAMS; i++) {
645             if(object->streamSource[i]) {
646                 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
647             }
648         }
649         if(object->vertexShader) {
650             IWineD3DVertexShader_AddRef(object->vertexShader);
651         }
652         object->pIndexData = NULL;
653         object->pixelShader = NULL;
654     } else {
655         FIXME("Unrecognized state block type %d\n", Type);
656     }
657
658     TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
659     return WINED3D_OK;
660 }
661
662 /* ************************************
663 MSDN:
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
665
666 Discard
667  [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise. 
668
669 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.
670
671 ******************************** */
672  
673 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) {
674     IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;    
675     IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676     unsigned int Size       = 1;
677     const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678     TRACE("(%p) Create surface\n",This);
679     
680     /** FIXME: Check ranges on the inputs are valid 
681      * MSDN
682      *   MultisampleQuality
683      *    [in] Quality level. The valid range is between zero and one less than the level
684      *    returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType. 
685      *    Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686      *    values of paired render targets, depth stencil surfaces, and the MultiSample type
687      *    must all match.
688       *******************************/
689
690
691     /**
692     * TODO: Discard MSDN
693     * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
694     *
695     * If this flag is set, the contents of the depth stencil buffer will be
696     * invalid after calling either IDirect3DDevice9::Present or  * IDirect3DDevice9::SetDepthStencilSurface
697     * with a different depth surface.
698     *
699     *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700     ***************************/
701
702     if(MultisampleQuality < 0) {
703         FIXME("Invalid multisample level %d\n", MultisampleQuality);
704         return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
705     }
706
707     if(MultisampleQuality > 0) {
708         FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709         MultisampleQuality=0;
710     }
711
712     /** FIXME: Check that the format is supported
713     *    by the device.
714       *******************************/
715
716     /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717      *  it is based around 4x4 pixel blocks it requires padding, so allocate enough
718      *  space!
719       *********************************/
720     if (WINED3DFMT_UNKNOWN == Format) {
721         Size = 0;
722     } else if (Format == WINED3DFMT_DXT1) {
723         /* DXT1 is half byte per pixel */
724        Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
725
726     } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727                Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728        Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
729     } else {
730        /* The pitch is a multiple of 4 bytes */
731         Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
732        Size *= Height;
733     }
734
735     /** Create and initialise the surface resource **/
736     D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737     /* "Standalone" surface */
738     IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
739
740     object->currentDesc.Width      = Width;
741     object->currentDesc.Height     = Height;
742     object->currentDesc.MultiSampleType    = MultiSample;
743     object->currentDesc.MultiSampleQuality = MultisampleQuality;
744     object->glDescription.level            = Level;
745
746     /* Flags */
747     object->Flags      = 0;
748     object->Flags     |= Discard ? SFLAG_DISCARD : 0;
749     object->Flags     |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750     object->Flags     |= Lockable ? SFLAG_LOCKABLE : 0;
751
752
753     if (WINED3DFMT_UNKNOWN != Format) {
754         object->bytesPerPixel = tableEntry->bpp;
755     } else {
756         object->bytesPerPixel = 0;
757     }
758
759     /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
760
761     TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
762
763     /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764     * this function is too deep to need to care about things like this.
765     * Levels need to be checked too, and possibly Type since they all affect what can be done.
766     * ****************************************/
767     switch(Pool) {
768     case WINED3DPOOL_SCRATCH:
769         if(!Lockable)
770             FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771                 "which are mutually exclusive, setting lockable to TRUE\n");
772                 Lockable = TRUE;
773     break;
774     case WINED3DPOOL_SYSTEMMEM:
775         if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776                                     "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777     case WINED3DPOOL_MANAGED:
778         if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779                                                 "Usage of DYNAMIC which are mutually exclusive, not doing "
780                                                 "anything just telling you.\n");
781     break;
782     case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783         if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784            && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785             WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
786     break;
787     default:
788         FIXME("(%p) Unknown pool %d\n", This, Pool);
789     break;
790     };
791
792     if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793         FIXME("Trying to create a render target that isn't in the default pool\n");
794     }
795
796     /* mark the texture as dirty so that it gets loaded first time around*/
797     IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798     TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799            This, Width, Height, Format, debug_d3dformat(Format),
800            (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
801
802     /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803     if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804         This->ddraw_primary = (IWineD3DSurface *) object;
805
806     /* Look at the implementation and set the correct Vtable */
807     switch(Impl) {
808         case SURFACE_OPENGL:
809             /* Check if a 3D adapter is available when creating gl surfaces */
810             if(!This->adapter) {
811                 ERR("OpenGL surfaces are not available without opengl\n");
812                 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813                 HeapFree(GetProcessHeap(), 0, object);
814                 return WINED3DERR_NOTAVAILABLE;
815             }
816             break;
817
818         case SURFACE_GDI:
819             object->lpVtbl = &IWineGDISurface_Vtbl;
820             break;
821
822         default:
823             /* To be sure to catch this */
824             ERR("Unknown requested surface implementation %d!\n", Impl);
825             IWineD3DSurface_Release((IWineD3DSurface *) object);
826             return WINED3DERR_INVALIDCALL;
827     }
828
829     list_init(&object->renderbuffers);
830
831     /* Call the private setup routine */
832     return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
833
834 }
835
836 static HRESULT  WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837                                                  DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838                                                  IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839                                                  D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
840
841     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842     IWineD3DTextureImpl *object;
843     unsigned int i;
844     UINT tmpW;
845     UINT tmpH;
846     HRESULT hr;
847     unsigned int pow2Width;
848     unsigned int pow2Height;
849
850
851     TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852     TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
853             Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
854
855     /* TODO: It should only be possible to create textures for formats 
856              that are reported as supported */
857     if (WINED3DFMT_UNKNOWN >= Format) {
858         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
859         return WINED3DERR_INVALIDCALL;
860     }
861
862     D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
863     D3DINITIALIZEBASETEXTURE(object->baseTexture);    
864     object->width  = Width;
865     object->height = Height;
866
867     /** Non-power2 support **/
868     if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
869         pow2Width = Width;
870         pow2Height = Height;
871     } else {
872         /* Find the nearest pow2 match */
873         pow2Width = pow2Height = 1;
874         while (pow2Width < Width) pow2Width <<= 1;
875         while (pow2Height < Height) pow2Height <<= 1;
876     }
877
878     /** FIXME: add support for real non-power-two if it's provided by the video card **/
879     /* Precalculated scaling for 'faked' non power of two texture coords */
880     object->pow2scalingFactorX  =  (((float)Width)  / ((float)pow2Width));
881     object->pow2scalingFactorY  =  (((float)Height) / ((float)pow2Height));
882     TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
883
884     /* Calculate levels for mip mapping */
885     if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
886         if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
887             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
888             return WINED3DERR_INVALIDCALL;
889         }
890         if(Levels > 1) {
891             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
892             return WINED3DERR_INVALIDCALL;
893         }
894         object->baseTexture.levels = 1;
895     } else if (Levels == 0) {
896         TRACE("calculating levels %d\n", object->baseTexture.levels);
897         object->baseTexture.levels++;
898         tmpW = Width;
899         tmpH = Height;
900         while (tmpW > 1 || tmpH > 1) {
901             tmpW = max(1, tmpW >> 1);
902             tmpH = max(1, tmpH >> 1);
903             object->baseTexture.levels++;
904         }
905         TRACE("Calculated levels = %d\n", object->baseTexture.levels);
906     }
907
908     /* Generate all the surfaces */
909     tmpW = Width;
910     tmpH = Height;
911     for (i = 0; i < object->baseTexture.levels; i++)
912     {
913         /* use the callback to create the texture surface */
914         hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
915         if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
916             FIXME("Failed to create surface  %p\n", object);
917             /* clean up */
918             object->surfaces[i] = NULL;
919             IWineD3DTexture_Release((IWineD3DTexture *)object);
920
921             *ppTexture = NULL;
922             return hr;
923         }
924
925         IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
926         TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
927         /* calculate the next mipmap level */
928         tmpW = max(1, tmpW >> 1);
929         tmpH = max(1, tmpH >> 1);
930     }
931
932     TRACE("(%p) : Created  texture %p\n", This, object);
933     return WINED3D_OK;
934 }
935
936 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
937                                                       UINT Width, UINT Height, UINT Depth,
938                                                       UINT Levels, DWORD Usage,
939                                                       WINED3DFORMAT Format, WINED3DPOOL Pool,
940                                                       IWineD3DVolumeTexture **ppVolumeTexture,
941                                                       HANDLE *pSharedHandle, IUnknown *parent,
942                                                       D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
943
944     IWineD3DDeviceImpl        *This = (IWineD3DDeviceImpl *)iface;
945     IWineD3DVolumeTextureImpl *object;
946     unsigned int               i;
947     UINT                       tmpW;
948     UINT                       tmpH;
949     UINT                       tmpD;
950
951     /* TODO: It should only be possible to create textures for formats 
952              that are reported as supported */
953     if (WINED3DFMT_UNKNOWN >= Format) {
954         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
955         return WINED3DERR_INVALIDCALL;
956     }
957
958     D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
959     D3DINITIALIZEBASETEXTURE(object->baseTexture);
960
961     TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
962           Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
963
964     object->width  = Width;
965     object->height = Height;
966     object->depth  = Depth;
967
968     /* Calculate levels for mip mapping */
969     if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
970         if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
971             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
972             return WINED3DERR_INVALIDCALL;
973         }
974         if(Levels > 1) {
975             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
976             return WINED3DERR_INVALIDCALL;
977         }
978         Levels = 1;
979     } else if (Levels == 0) {
980         object->baseTexture.levels++;
981         tmpW = Width;
982         tmpH = Height;
983         tmpD = Depth;
984         while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
985             tmpW = max(1, tmpW >> 1);
986             tmpH = max(1, tmpH >> 1);
987             tmpD = max(1, tmpD >> 1);
988             object->baseTexture.levels++;
989         }
990         TRACE("Calculated levels = %d\n", object->baseTexture.levels);
991     }
992
993     /* Generate all the surfaces */
994     tmpW = Width;
995     tmpH = Height;
996     tmpD = Depth;
997
998     for (i = 0; i < object->baseTexture.levels; i++)
999     {
1000         HRESULT hr;
1001         /* Create the volume */
1002         hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1003                                 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1004
1005         if(FAILED(hr)) {
1006             ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1007             IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1008             *ppVolumeTexture = NULL;
1009             return hr;
1010         }
1011
1012         /* Set its container to this object */
1013         IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1014
1015         /* calcualte the next mipmap level */
1016         tmpW = max(1, tmpW >> 1);
1017         tmpH = max(1, tmpH >> 1);
1018         tmpD = max(1, tmpD >> 1);
1019     }
1020
1021     *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1022     TRACE("(%p) : Created volume texture %p\n", This, object);
1023     return WINED3D_OK;
1024 }
1025
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1027                                                UINT Width, UINT Height, UINT Depth,
1028                                                DWORD Usage,
1029                                                WINED3DFORMAT Format, WINED3DPOOL Pool,
1030                                                IWineD3DVolume** ppVolume,
1031                                                HANDLE* pSharedHandle, IUnknown *parent) {
1032
1033     IWineD3DDeviceImpl        *This = (IWineD3DDeviceImpl *)iface;
1034     IWineD3DVolumeImpl        *object; /** NOTE: impl ref allowed since this is a create function **/
1035     const StaticPixelFormatDesc *formatDesc  = getFormatDescEntry(Format, NULL, NULL);
1036
1037     D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1038
1039     TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1040           Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1041
1042     object->currentDesc.Width   = Width;
1043     object->currentDesc.Height  = Height;
1044     object->currentDesc.Depth   = Depth;
1045     object->bytesPerPixel       = formatDesc->bpp;
1046
1047     /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1048     object->lockable            = TRUE;
1049     object->locked              = FALSE;
1050     memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1051     object->dirty               = TRUE;
1052
1053     return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1054 }
1055
1056 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1057                                                     UINT Levels, DWORD Usage,
1058                                                     WINED3DFORMAT Format, WINED3DPOOL Pool,
1059                                                     IWineD3DCubeTexture **ppCubeTexture,
1060                                                     HANDLE *pSharedHandle, IUnknown *parent,
1061                                                     D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1062
1063     IWineD3DDeviceImpl      *This = (IWineD3DDeviceImpl *)iface;
1064     IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1065     unsigned int             i, j;
1066     UINT                     tmpW;
1067     HRESULT                  hr;
1068     unsigned int pow2EdgeLength  = EdgeLength;
1069
1070     /* TODO: It should only be possible to create textures for formats 
1071              that are reported as supported */
1072     if (WINED3DFMT_UNKNOWN >= Format) {
1073         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1074         return WINED3DERR_INVALIDCALL;
1075     }
1076
1077     if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1078         WARN("(%p) : Tried to create not supported cube texture\n", This);
1079         return WINED3DERR_INVALIDCALL;
1080     }
1081
1082     D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1083     D3DINITIALIZEBASETEXTURE(object->baseTexture);
1084
1085     TRACE("(%p) Create Cube Texture\n", This);
1086
1087     /** Non-power2 support **/
1088
1089     /* Find the nearest pow2 match */
1090     pow2EdgeLength = 1;
1091     while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1092
1093     object->edgeLength           = EdgeLength;
1094     /* TODO: support for native non-power 2 */
1095     /* Precalculated scaling for 'faked' non power of two texture coords */
1096     object->pow2scalingFactor    = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097
1098     /* Calculate levels for mip mapping */
1099     if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1100         if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1101             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1102             return WINED3DERR_INVALIDCALL;
1103         }
1104         if(Levels > 1) {
1105             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106             return WINED3DERR_INVALIDCALL;
1107         }
1108         Levels = 1;
1109     } else if (Levels == 0) {
1110         object->baseTexture.levels++;
1111         tmpW = EdgeLength;
1112         while (tmpW > 1) {
1113             tmpW = max(1, tmpW >> 1);
1114             object->baseTexture.levels++;
1115         }
1116         TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1117     }
1118
1119     /* Generate all the surfaces */
1120     tmpW = EdgeLength;
1121     for (i = 0; i < object->baseTexture.levels; i++) {
1122
1123         /* Create the 6 faces */
1124         for (j = 0; j < 6; j++) {
1125
1126             hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1127                                    i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1128
1129             if(hr!= WINED3D_OK) {
1130                 /* clean up */
1131                 int k;
1132                 int l;
1133                 for (l = 0; l < j; l++) {
1134                     IWineD3DSurface_Release(object->surfaces[j][i]);
1135                 }
1136                 for (k = 0; k < i; k++) {
1137                     for (l = 0; l < 6; l++) {
1138                     IWineD3DSurface_Release(object->surfaces[l][j]);
1139                     }
1140                 }
1141
1142                 FIXME("(%p) Failed to create surface\n",object);
1143                 HeapFree(GetProcessHeap(),0,object);
1144                 *ppCubeTexture = NULL;
1145                 return hr;
1146             }
1147             IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1148             TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1149         }
1150         tmpW = max(1, tmpW >> 1);
1151     }
1152
1153     TRACE("(%p) : Created Cube Texture %p\n", This, object);
1154     *ppCubeTexture = (IWineD3DCubeTexture *) object;
1155     return WINED3D_OK;
1156 }
1157
1158 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1159     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1160     IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1161     HRESULT hr = WINED3DERR_NOTAVAILABLE;
1162
1163     /* Just a check to see if we support this type of query */
1164     switch(Type) {
1165     case WINED3DQUERYTYPE_OCCLUSION:
1166         TRACE("(%p) occlusion query\n", This);
1167         if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1168             hr = WINED3D_OK;
1169         else
1170             WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1171         break;
1172
1173     case WINED3DQUERYTYPE_EVENT:
1174         if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1175             /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1176              * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1177              */
1178             FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1179         }
1180         hr = WINED3D_OK;
1181         break;
1182
1183     case WINED3DQUERYTYPE_VCACHE:
1184     case WINED3DQUERYTYPE_RESOURCEMANAGER:
1185     case WINED3DQUERYTYPE_VERTEXSTATS:
1186     case WINED3DQUERYTYPE_TIMESTAMP:
1187     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1188     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1189     case WINED3DQUERYTYPE_PIPELINETIMINGS:
1190     case WINED3DQUERYTYPE_INTERFACETIMINGS:
1191     case WINED3DQUERYTYPE_VERTEXTIMINGS:
1192     case WINED3DQUERYTYPE_PIXELTIMINGS:
1193     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1194     case WINED3DQUERYTYPE_CACHEUTILIZATION:
1195     default:
1196         FIXME("(%p) Unhandled query type %d\n", This, Type);
1197     }
1198     if(NULL == ppQuery || hr != WINED3D_OK) {
1199         return hr;
1200     }
1201
1202     D3DCREATEOBJECTINSTANCE(object, Query)
1203     object->type         = Type;
1204     /* allocated the 'extended' data based on the type of query requested */
1205     switch(Type){
1206     case WINED3DQUERYTYPE_OCCLUSION:
1207         if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1208             TRACE("(%p) Allocating data for an occlusion query\n", This);
1209             object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1210             GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1211             ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1212             break;
1213         }
1214     case WINED3DQUERYTYPE_EVENT:
1215         if(GL_SUPPORT(APPLE_FENCE)) {
1216             object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1217             GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1218             checkGLcall("glGenFencesAPPLE");
1219             ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1220         } else if(GL_SUPPORT(NV_FENCE)) {
1221             object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1222             GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1223             checkGLcall("glGenFencesNV");
1224             ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1225         }
1226         break;
1227
1228     case WINED3DQUERYTYPE_VCACHE:
1229     case WINED3DQUERYTYPE_RESOURCEMANAGER:
1230     case WINED3DQUERYTYPE_VERTEXSTATS:
1231     case WINED3DQUERYTYPE_TIMESTAMP:
1232     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1233     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1234     case WINED3DQUERYTYPE_PIPELINETIMINGS:
1235     case WINED3DQUERYTYPE_INTERFACETIMINGS:
1236     case WINED3DQUERYTYPE_VERTEXTIMINGS:
1237     case WINED3DQUERYTYPE_PIXELTIMINGS:
1238     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1239     case WINED3DQUERYTYPE_CACHEUTILIZATION:
1240     default:
1241         object->extendedData = 0;
1242         FIXME("(%p) Unhandled query type %d\n",This , Type);
1243     }
1244     TRACE("(%p) : Created Query %p\n", This, object);
1245     return WINED3D_OK;
1246 }
1247
1248 /*****************************************************************************
1249  * IWineD3DDeviceImpl_SetupFullscreenWindow
1250  *
1251  * Helper function that modifies a HWND's Style and ExStyle for proper
1252  * fullscreen use.
1253  *
1254  * Params:
1255  *  iface: Pointer to the IWineD3DDevice interface
1256  *  window: Window to setup
1257  *
1258  *****************************************************************************/
1259 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1260     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1261
1262     LONG style, exStyle;
1263     /* Don't do anything if an original style is stored.
1264      * That shouldn't happen
1265      */
1266     TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1267     if (This->style || This->exStyle) {
1268         ERR("(%p): Want to change the window parameters of HWND %p, but "
1269             "another style is stored for restoration afterwards\n", This, window);
1270     }
1271
1272     /* Get the parameters and save them */
1273     style = GetWindowLongW(window, GWL_STYLE);
1274     exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1275     This->style = style;
1276     This->exStyle = exStyle;
1277
1278     /* Filter out window decorations */
1279     style &= ~WS_CAPTION;
1280     style &= ~WS_THICKFRAME;
1281     exStyle &= ~WS_EX_WINDOWEDGE;
1282     exStyle &= ~WS_EX_CLIENTEDGE;
1283
1284     /* Make sure the window is managed, otherwise we won't get keyboard input */
1285     style |= WS_POPUP | WS_SYSMENU;
1286
1287     TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1288           This->style, This->exStyle, style, exStyle);
1289
1290     SetWindowLongW(window, GWL_STYLE, style);
1291     SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1292
1293     /* Inform the window about the update. */
1294     SetWindowPos(window, HWND_TOP, 0, 0,
1295             This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1296     ShowWindow(window, SW_NORMAL);
1297 }
1298
1299 /*****************************************************************************
1300  * IWineD3DDeviceImpl_RestoreWindow
1301  *
1302  * Helper function that restores a windows' properties when taking it out
1303  * of fullscreen mode
1304  *
1305  * Params:
1306  *  iface: Pointer to the IWineD3DDevice interface
1307  *  window: Window to setup
1308  *
1309  *****************************************************************************/
1310 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1311     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1312
1313     /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1314      * switch, do nothing
1315      */
1316     if (!This->style && !This->exStyle) return;
1317
1318     TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1319           This, window, This->style, This->exStyle);
1320
1321     SetWindowLongW(window, GWL_STYLE, This->style);
1322     SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1323
1324     /* Delete the old values */
1325     This->style = 0;
1326     This->exStyle = 0;
1327
1328     /* Inform the window about the update */
1329     SetWindowPos(window, 0 /* InsertAfter, ignored */,
1330                  0, 0, 0, 0, /* Pos, Size, ignored */
1331                  SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1332 }
1333
1334 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS*  pPresentationParameters,                                                                   IWineD3DSwapChain** ppSwapChain,
1336                                                             IUnknown* parent,
1337                                                             D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1338                                                             D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1339     IWineD3DDeviceImpl      *This = (IWineD3DDeviceImpl *)iface;
1340
1341     HDC                     hDc;
1342     IWineD3DSwapChainImpl  *object; /** NOTE: impl ref allowed since this is a create function **/
1343     HRESULT                 hr = WINED3D_OK;
1344     IUnknown               *bufferParent;
1345
1346     TRACE("(%p) : Created Aditional Swap Chain\n", This);
1347
1348    /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1349    * does a device hold a reference to a swap chain giving them a lifetime of the device
1350    * or does the swap chain notify the device of its destruction.
1351     *******************************/
1352
1353     /* Check the params */
1354     if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1355         ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1356         return WINED3DERR_INVALIDCALL;
1357     } else if (pPresentationParameters->BackBufferCount > 1) {
1358         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");
1359     }
1360
1361     D3DCREATEOBJECTINSTANCE(object, SwapChain)
1362
1363     /*********************
1364     * Lookup the window Handle and the relating X window handle
1365     ********************/
1366
1367     /* Setup hwnd we are using, plus which display this equates to */
1368     object->win_handle = pPresentationParameters->hDeviceWindow;
1369     if (!object->win_handle) {
1370         object->win_handle = This->createParms.hFocusWindow;
1371     }
1372
1373     object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1374     hDc                = GetDC(object->win_handle);
1375     TRACE("Using hDc %p\n", hDc);
1376
1377     if (NULL == hDc) {
1378         WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1379         return WINED3DERR_NOTAVAILABLE;
1380     }
1381
1382     object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1383     object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1384     object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1385     ReleaseDC(object->win_handle, hDc);
1386
1387     /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1388      *  then the corresponding dimension of the client area of the hDeviceWindow
1389      *  (or the focus window, if hDeviceWindow is NULL) is taken.
1390       **********************/
1391
1392     if (pPresentationParameters->Windowed &&
1393         ((pPresentationParameters->BackBufferWidth == 0) ||
1394          (pPresentationParameters->BackBufferHeight == 0) ||
1395          (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1396
1397         RECT Rect;
1398         GetClientRect(object->win_handle, &Rect);
1399
1400         if (pPresentationParameters->BackBufferWidth == 0) {
1401            pPresentationParameters->BackBufferWidth = Rect.right;
1402            TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1403         }
1404         if (pPresentationParameters->BackBufferHeight == 0) {
1405            pPresentationParameters->BackBufferHeight = Rect.bottom;
1406            TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1407         }
1408         if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1409            pPresentationParameters->BackBufferFormat = object->orig_fmt;
1410            TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1411         }
1412     }
1413
1414     /* Put the correct figures in the presentation parameters */
1415     TRACE("Copying across presentation parameters\n");
1416     object->presentParms = *pPresentationParameters;
1417
1418     TRACE("calling rendertarget CB\n");
1419     hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1420                              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->frontBuffer,
1428                              NULL /* pShared (always null)*/);
1429     if (object->frontBuffer != NULL) {
1430         IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1431     } else {
1432         ERR("Failed to create the front buffer\n");
1433         goto error;
1434     }
1435
1436     /**
1437     * Create an opengl context for the display visual
1438     *  NOTE: the visual is chosen as the window is created and the glcontext cannot
1439     *     use different properties after that point in time. FIXME: How to handle when requested format
1440     *     doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1441     *     it chooses is identical to the one already being used!
1442      **********************************/
1443     /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1444
1445     object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1446     if(!object->context)
1447         return E_OUTOFMEMORY;
1448     object->num_contexts = 1;
1449
1450     ENTER_GL();
1451     object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1452     LEAVE_GL();
1453
1454     if (!object->context[0]) {
1455         ERR("Failed to create a new context\n");
1456         hr = WINED3DERR_NOTAVAILABLE;
1457         goto error;
1458     } else {
1459         TRACE("Context created (HWND=%p, glContext=%p)\n",
1460                object->win_handle, object->context[0]->glCtx);
1461     }
1462
1463    /*********************
1464    * Windowed / Fullscreen
1465    *******************/
1466
1467    /**
1468    * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1469    * so we should really check to see if there is a fullscreen swapchain already
1470    * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1471     **************************************/
1472
1473    if (!pPresentationParameters->Windowed) {
1474
1475         DEVMODEW devmode;
1476         HDC      hdc;
1477         int      bpp = 0;
1478         RECT     clip_rc;
1479
1480         /* Get info on the current display setup */
1481         hdc = GetDC(0);
1482         bpp = GetDeviceCaps(hdc, BITSPIXEL);
1483         ReleaseDC(0, hdc);
1484
1485         /* Change the display settings */
1486         memset(&devmode, 0, sizeof(devmode));
1487         devmode.dmSize       = sizeof(devmode);
1488         devmode.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1489         devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1490         devmode.dmPelsWidth  = pPresentationParameters->BackBufferWidth;
1491         devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1492         ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1493
1494         /* For GetDisplayMode */
1495         This->ddraw_width = devmode.dmPelsWidth;
1496         This->ddraw_height = devmode.dmPelsHeight;
1497         This->ddraw_format = pPresentationParameters->BackBufferFormat;
1498
1499         IWineD3DDevice_SetFullscreen(iface, TRUE);
1500
1501         /* And finally clip mouse to our screen */
1502         SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1503         ClipCursor(&clip_rc);
1504     }
1505
1506    /*********************
1507    * Create the back, front and stencil buffers
1508    *******************/
1509     if(object->presentParms.BackBufferCount > 0) {
1510         int i;
1511
1512         object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1513         if(!object->backBuffer) {
1514             ERR("Out of memory\n");
1515             hr = E_OUTOFMEMORY;
1516             goto error;
1517         }
1518
1519         for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1520             TRACE("calling rendertarget CB\n");
1521             hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1522                                     parent,
1523                                     object->presentParms.BackBufferWidth,
1524                                     object->presentParms.BackBufferHeight,
1525                                     object->presentParms.BackBufferFormat,
1526                                     object->presentParms.MultiSampleType,
1527                                     object->presentParms.MultiSampleQuality,
1528                                     TRUE /* Lockable */,
1529                                     &object->backBuffer[i],
1530                                     NULL /* pShared (always null)*/);
1531             if(hr == WINED3D_OK && object->backBuffer[i]) {
1532                 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1533             } else {
1534                 ERR("Cannot create new back buffer\n");
1535                 goto error;
1536             }
1537             ENTER_GL();
1538             glDrawBuffer(GL_BACK);
1539             checkGLcall("glDrawBuffer(GL_BACK)");
1540             LEAVE_GL();
1541         }
1542     } else {
1543         object->backBuffer = NULL;
1544
1545         /* Single buffering - draw to front buffer */
1546         ENTER_GL();
1547         glDrawBuffer(GL_FRONT);
1548         checkGLcall("glDrawBuffer(GL_FRONT)");
1549         LEAVE_GL();
1550     }
1551
1552     /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1553     if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1554         TRACE("Creating depth stencil buffer\n");
1555         if (This->depthStencilBuffer == NULL ) {
1556             hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1557                                     parent,
1558                                     object->presentParms.BackBufferWidth,
1559                                     object->presentParms.BackBufferHeight,
1560                                     object->presentParms.AutoDepthStencilFormat,
1561                                     object->presentParms.MultiSampleType,
1562                                     object->presentParms.MultiSampleQuality,
1563                                     FALSE /* FIXME: Discard */,
1564                                     &This->depthStencilBuffer,
1565                                     NULL /* pShared (always null)*/  );
1566             if (This->depthStencilBuffer != NULL)
1567                 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1568         }
1569
1570         /** TODO: A check on width, height and multisample types
1571         *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1572          ****************************/
1573         object->wantsDepthStencilBuffer = TRUE;
1574     } else {
1575         object->wantsDepthStencilBuffer = FALSE;
1576     }
1577
1578     TRACE("Created swapchain %p\n", object);
1579     TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1580     return WINED3D_OK;
1581
1582 error:
1583     if (object->backBuffer) {
1584         int i;
1585         for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1586             if(object->backBuffer[i]) {
1587                 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1588                 IUnknown_Release(bufferParent); /* once for the get parent */
1589                 if (IUnknown_Release(bufferParent) > 0) {
1590                     FIXME("(%p) Something's still holding the back buffer\n",This);
1591                 }
1592             }
1593         }
1594         HeapFree(GetProcessHeap(), 0, object->backBuffer);
1595         object->backBuffer = NULL;
1596     }
1597     if(object->context[0])
1598         DestroyContext(This, object->context[0]);
1599     if(object->frontBuffer) {
1600         IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1601         IUnknown_Release(bufferParent); /* once for the get parent */
1602         if (IUnknown_Release(bufferParent) > 0) {
1603             FIXME("(%p) Something's still holding the front buffer\n",This);
1604         }
1605     }
1606     HeapFree(GetProcessHeap(), 0, object);
1607     return hr;
1608 }
1609
1610 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1611 static UINT     WINAPI  IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1612     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1613     TRACE("(%p)\n", This);
1614
1615     return This->NumberOfSwapChains;
1616 }
1617
1618 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1619     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1620     TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1621
1622     if(iSwapChain < This->NumberOfSwapChains) {
1623         *pSwapChain = This->swapchains[iSwapChain];
1624         IWineD3DSwapChain_AddRef(*pSwapChain);
1625         TRACE("(%p) returning %p\n", This, *pSwapChain);
1626         return WINED3D_OK;
1627     } else {
1628         TRACE("Swapchain out of range\n");
1629         *pSwapChain = NULL;
1630         return WINED3DERR_INVALIDCALL;
1631     }
1632 }
1633
1634 /*****
1635  * Vertex Declaration
1636  *****/
1637 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1638         IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1639     IWineD3DDeviceImpl            *This   = (IWineD3DDeviceImpl *)iface;
1640     IWineD3DVertexDeclarationImpl *object = NULL;
1641     HRESULT hr = WINED3D_OK;
1642
1643     TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1644             This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1645
1646     D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1647
1648     hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1649
1650     return hr;
1651 }
1652
1653 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1654
1655     unsigned int idx, idx2;
1656     unsigned int offset;
1657     BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1658     BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1659     BOOL has_blend_idx = has_blend &&
1660        (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1661         (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1662         (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1663     BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1664     BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1665     BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1666     BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1667
1668     DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1669     DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1670
1671     WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1672     WINED3DVERTEXELEMENT *elements = NULL;
1673
1674     unsigned int size;
1675     DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1676     if (has_blend_idx) num_blends--;
1677
1678     /* Compute declaration size */
1679     size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1680            has_psize + has_diffuse + has_specular + num_textures + 1;
1681
1682     /* convert the declaration */
1683     elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1684     if (!elements)
1685         return 0;
1686
1687     memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1688     idx = 0;
1689     if (has_pos) {
1690         if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1691             elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1692             elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1693         }
1694         else {
1695             elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1696             elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1697         }
1698         elements[idx].UsageIndex = 0;
1699         idx++;
1700     }
1701     if (has_blend && (num_blends > 0)) {
1702         if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1703             elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1704         else
1705             elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1706         elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1707         elements[idx].UsageIndex = 0;
1708         idx++;
1709     }
1710     if (has_blend_idx) {
1711         if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1712             (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1713             elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1714         else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1715             elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1716         else
1717             elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1718         elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1719         elements[idx].UsageIndex = 0;
1720         idx++;
1721     }
1722     if (has_normal) {
1723         elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1724         elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1725         elements[idx].UsageIndex = 0;
1726         idx++;
1727     }
1728     if (has_psize) {
1729         elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1730         elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1731         elements[idx].UsageIndex = 0;
1732         idx++;
1733     }
1734     if (has_diffuse) {
1735         elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1736         elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1737         elements[idx].UsageIndex = 0;
1738         idx++;
1739     }
1740     if (has_specular) {
1741         elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1742         elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1743         elements[idx].UsageIndex = 1;
1744         idx++;
1745     }
1746     for (idx2 = 0; idx2 < num_textures; idx2++) {
1747         unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1748         switch (numcoords) {
1749             case WINED3DFVF_TEXTUREFORMAT1:
1750                 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1751                 break;
1752             case WINED3DFVF_TEXTUREFORMAT2:
1753                 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1754                 break;
1755             case WINED3DFVF_TEXTUREFORMAT3:
1756                 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1757                 break;
1758             case WINED3DFVF_TEXTUREFORMAT4:
1759                 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1760                 break;
1761         }
1762         elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1763         elements[idx].UsageIndex = idx2;
1764         idx++;
1765     }
1766
1767     /* Now compute offsets, and initialize the rest of the fields */
1768     for (idx = 0, offset = 0; idx < size-1; idx++) {
1769         elements[idx].Stream = 0;
1770         elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1771         elements[idx].Offset = offset;
1772         offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1773     }
1774
1775     *ppVertexElements = elements;
1776     return size;
1777 }
1778
1779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1780     WINED3DVERTEXELEMENT* elements = NULL;
1781     size_t size;
1782     DWORD hr;
1783
1784     size = ConvertFvfToDeclaration(Fvf, &elements);
1785     if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1786
1787     hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1788     HeapFree(GetProcessHeap(), 0, elements);
1789     if (hr != S_OK) return hr;
1790
1791     return WINED3D_OK;
1792 }
1793
1794 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1795 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1796     IWineD3DDeviceImpl       *This = (IWineD3DDeviceImpl *)iface;
1797     IWineD3DVertexShaderImpl *object;  /* NOTE: impl usage is ok, this is a create */
1798     HRESULT hr = WINED3D_OK;
1799     D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1800     object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1801
1802     TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1803
1804     if (vertex_declaration) {
1805         IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1806     }
1807
1808     hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1809
1810     if (WINED3D_OK != hr) {
1811         FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1812         IWineD3DVertexShader_Release(*ppVertexShader);
1813         return WINED3DERR_INVALIDCALL;
1814     }
1815
1816     return WINED3D_OK;
1817 }
1818
1819 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1820     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821     IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1822     HRESULT hr = WINED3D_OK;
1823
1824     D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1825     object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1826     hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1827     if (WINED3D_OK == hr) {
1828         TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1829     } else {
1830         WARN("(%p) : Failed to create pixel shader\n", This);
1831     }
1832
1833     return hr;
1834 }
1835
1836 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1837     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1838     IWineD3DPaletteImpl *object;
1839     HRESULT hr;
1840     TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1841
1842     /* Create the new object */
1843     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1844     if(!object) {
1845         ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1846         return E_OUTOFMEMORY;
1847     }
1848
1849     object->lpVtbl = &IWineD3DPalette_Vtbl;
1850     object->ref = 1;
1851     object->Flags = Flags;
1852     object->parent = Parent;
1853     object->wineD3DDevice = This;
1854     object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1855         
1856     object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1857
1858     if(!object->hpal) {
1859         HeapFree( GetProcessHeap(), 0, object);
1860         return E_OUTOFMEMORY;
1861     }
1862
1863     hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1864     if(FAILED(hr)) {
1865         IWineD3DPalette_Release((IWineD3DPalette *) object);
1866         return hr;
1867     }
1868
1869     *Palette = (IWineD3DPalette *) object;
1870
1871     return WINED3D_OK;
1872 }
1873
1874 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1875     HBITMAP hbm;
1876     BITMAP bm;
1877     HRESULT hr;
1878     HDC dcb = NULL, dcs = NULL;
1879     WINEDDCOLORKEY colorkey;
1880
1881     hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1882     if(hbm)
1883     {
1884         GetObjectA(hbm, sizeof(BITMAP), &bm);
1885         dcb = CreateCompatibleDC(NULL);
1886         if(!dcb) goto out;
1887         SelectObject(dcb, hbm);
1888     }
1889     else
1890     {
1891         /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1892          * couldn't be loaded
1893          */
1894         memset(&bm, 0, sizeof(bm));
1895         bm.bmWidth = 32;
1896         bm.bmHeight = 32;
1897     }
1898
1899     hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1900                                       TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1901                                       WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1902     if(FAILED(hr)) {
1903         ERR("Wine logo requested, but failed to create surface\n");
1904         goto out;
1905     }
1906
1907     if(dcb) {
1908         hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1909         if(FAILED(hr)) goto out;
1910         BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1911         IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1912
1913         colorkey.dwColorSpaceLowValue = 0;
1914         colorkey.dwColorSpaceHighValue = 0;
1915         IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1916     } else {
1917         /* Fill the surface with a white color to show that wined3d is there */
1918         IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1919     }
1920
1921     out:
1922     if(dcb) {
1923         DeleteDC(dcb);
1924     }
1925     if(hbm) {
1926         DeleteObject(hbm);
1927     }
1928     return;
1929 }
1930
1931 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1932     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1933     IWineD3DSwapChainImpl *swapchain;
1934     HRESULT hr;
1935     DWORD state;
1936
1937     TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1938     if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1939
1940     /* TODO: Test if OpenGL is compiled in and loaded */
1941
1942     TRACE("(%p) : Creating stateblock\n", This);
1943     /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1944     hr = IWineD3DDevice_CreateStateBlock(iface,
1945                                          WINED3DSBT_INIT,
1946                                          (IWineD3DStateBlock **)&This->stateBlock,
1947                                          NULL);
1948     if (WINED3D_OK != hr) {   /* Note: No parent needed for initial internal stateblock */
1949         WARN("Failed to create stateblock\n");
1950         return hr;
1951     }
1952     TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1953     This->updateStateBlock = This->stateBlock;
1954     IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1955
1956     hr = allocate_shader_constants(This->updateStateBlock);
1957     if (WINED3D_OK != hr)
1958         return hr;
1959
1960     This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1961     This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1962     This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1963
1964     /* Initialize the texture unit mapping to a 1:1 mapping */
1965     for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1966         if (state < GL_LIMITS(fragment_samplers)) {
1967             This->texUnitMap[state] = state;
1968             This->rev_tex_unit_map[state] = state;
1969         } else {
1970             This->texUnitMap[state] = -1;
1971             This->rev_tex_unit_map[state] = -1;
1972         }
1973     }
1974
1975     /* Setup the implicit swapchain */
1976     TRACE("Creating implicit swapchain\n");
1977     hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1978     if (FAILED(hr) || !swapchain) {
1979         WARN("Failed to create implicit swapchain\n");
1980         return hr;
1981     }
1982
1983     This->NumberOfSwapChains = 1;
1984     This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1985     if(!This->swapchains) {
1986         ERR("Out of memory!\n");
1987         IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1988         return E_OUTOFMEMORY;
1989     }
1990     This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1991
1992     if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1993
1994     if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1995         TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1996         This->render_targets[0] = swapchain->backBuffer[0];
1997         This->lastActiveRenderTarget = swapchain->backBuffer[0];
1998     }
1999     else {
2000         TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2001         This->render_targets[0] = swapchain->frontBuffer;
2002         This->lastActiveRenderTarget = swapchain->frontBuffer;
2003     }
2004     IWineD3DSurface_AddRef(This->render_targets[0]);
2005     This->activeContext = swapchain->context[0];
2006     This->lastThread = GetCurrentThreadId();
2007
2008     /* Depth Stencil support */
2009     This->stencilBufferTarget = This->depthStencilBuffer;
2010     if (NULL != This->stencilBufferTarget) {
2011         IWineD3DSurface_AddRef(This->stencilBufferTarget);
2012     }
2013
2014     /* Set up some starting GL setup */
2015     ENTER_GL();
2016
2017     /* Setup all the devices defaults */
2018     IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2019 #if 0
2020     IWineD3DImpl_CheckGraphicsMemory();
2021 #endif
2022
2023     { /* Set a default viewport */
2024         WINED3DVIEWPORT vp;
2025         vp.X      = 0;
2026         vp.Y      = 0;
2027         vp.Width  = pPresentationParameters->BackBufferWidth;
2028         vp.Height = pPresentationParameters->BackBufferHeight;
2029         vp.MinZ   = 0.0f;
2030         vp.MaxZ   = 1.0f;
2031         IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2032     }
2033
2034     /* Initialize the current view state */
2035     This->view_ident = 1;
2036     This->contexts[0]->last_was_rhw = 0;
2037     glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2038     checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2039
2040     switch(wined3d_settings.offscreen_rendering_mode) {
2041         case ORM_FBO:
2042         case ORM_PBUFFER:
2043             This->offscreenBuffer = GL_BACK;
2044             break;
2045
2046         case ORM_BACKBUFFER:
2047         {
2048             if(GL_LIMITS(aux_buffers) > 0) {
2049                 TRACE("Using auxilliary buffer for offscreen rendering\n");
2050                 This->offscreenBuffer = GL_AUX0;
2051             } else {
2052                 TRACE("Using back buffer for offscreen rendering\n");
2053                 This->offscreenBuffer = GL_BACK;
2054             }
2055         }
2056     }
2057
2058     TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2059     LEAVE_GL();
2060
2061     /* Clear the screen */
2062     IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2063                           WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2064                           0x00, 1.0, 0);
2065
2066     This->d3d_initialized = TRUE;
2067
2068     if(wined3d_settings.logo) {
2069         IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2070     }
2071     return WINED3D_OK;
2072 }
2073
2074 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2075     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2076     int sampler;
2077     UINT i;
2078     TRACE("(%p)\n", This);
2079
2080     if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2081
2082     /* I don't think that the interface guarants that the device is destroyed from the same thread
2083      * it was created. Thus make sure a context is active for the glDelete* calls
2084      */
2085     ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2086
2087     if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2088
2089     TRACE("Deleting high order patches\n");
2090     for(i = 0; i < PATCHMAP_SIZE; i++) {
2091         struct list *e1, *e2;
2092         struct WineD3DRectPatch *patch;
2093         LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2094             patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2095             IWineD3DDevice_DeletePatch(iface, patch->Handle);
2096         }
2097     }
2098
2099     /* Delete the pbuffer context if there is any */
2100     if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2101
2102     /* Delete the mouse cursor texture */
2103     if(This->cursorTexture) {
2104         ENTER_GL();
2105         glDeleteTextures(1, &This->cursorTexture);
2106         LEAVE_GL();
2107         This->cursorTexture = 0;
2108     }
2109
2110     for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2111         IWineD3DDevice_SetTexture(iface, sampler, NULL);
2112     }
2113     for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2114         IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2115     }
2116
2117     /* Release the update stateblock */
2118     if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2119         if(This->updateStateBlock != This->stateBlock)
2120             FIXME("(%p) Something's still holding the Update stateblock\n",This);
2121     }
2122     This->updateStateBlock = NULL;
2123
2124     { /* because were not doing proper internal refcounts releasing the primary state block
2125         causes recursion with the extra checks in ResourceReleased, to avoid this we have
2126         to set this->stateBlock = NULL; first */
2127         IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2128         This->stateBlock = NULL;
2129
2130         /* Release the stateblock */
2131         if(IWineD3DStateBlock_Release(stateBlock) > 0){
2132             FIXME("(%p) Something's still holding the Update stateblock\n",This);
2133         }
2134     }
2135
2136     /* Release the buffers (with sanity checks)*/
2137     TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2138     if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2139         if(This->depthStencilBuffer != This->stencilBufferTarget)
2140             FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2141     }
2142     This->stencilBufferTarget = NULL;
2143
2144     TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2145     if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2146           /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2147     }
2148     TRACE("Setting rendertarget to NULL\n");
2149     This->render_targets[0] = NULL;
2150
2151     if (This->depthStencilBuffer) {
2152         if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2153             FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2154         }
2155         This->depthStencilBuffer = NULL;
2156     }
2157
2158     for(i=0; i < This->NumberOfSwapChains; i++) {
2159         TRACE("Releasing the implicit swapchain %d\n", i);
2160         if (D3DCB_DestroySwapChain(This->swapchains[i])  > 0) {
2161             FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2162         }
2163     }
2164
2165     HeapFree(GetProcessHeap(), 0, This->swapchains);
2166     This->swapchains = NULL;
2167     This->NumberOfSwapChains = 0;
2168
2169     HeapFree(GetProcessHeap(), 0, This->render_targets);
2170     HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2171     HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2172     This->render_targets = NULL;
2173     This->fbo_color_attachments = NULL;
2174     This->draw_buffers = NULL;
2175
2176
2177     This->d3d_initialized = FALSE;
2178     return WINED3D_OK;
2179 }
2180
2181 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2182     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2183     TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2184
2185     /* Setup the window for fullscreen mode */
2186     if(fullscreen && !This->ddraw_fullscreen) {
2187         IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2188     } else if(!fullscreen && This->ddraw_fullscreen) {
2189         IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2190     }
2191
2192     /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2193      * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2194      * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2195      * separately.
2196      */
2197     This->ddraw_fullscreen = fullscreen;
2198 }
2199
2200 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2201  * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2202  * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2203  *
2204  * There is no way to deactivate thread safety once it is enabled
2205  */
2206 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2207     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2208
2209     /*For now just store the flag(needed in case of ddraw) */
2210     This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2211
2212     return;
2213 }
2214
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2216     DEVMODEW devmode;
2217     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218     LONG ret;
2219     const StaticPixelFormatDesc *formatDesc  = getFormatDescEntry(pMode->Format, NULL, NULL);
2220     RECT clip_rc;
2221
2222     TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2223
2224     /* Resize the screen even without a window:
2225      * The app could have unset it with SetCooperativeLevel, but not called
2226      * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2227      * but we don't have any hwnd
2228      */
2229
2230     memset(&devmode, 0, sizeof(devmode));
2231     devmode.dmSize = sizeof(devmode);
2232     devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2233     devmode.dmBitsPerPel = formatDesc->bpp * 8;
2234     if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2235     devmode.dmPelsWidth  = pMode->Width;
2236     devmode.dmPelsHeight = pMode->Height;
2237
2238     devmode.dmDisplayFrequency = pMode->RefreshRate;
2239     if (pMode->RefreshRate != 0)  {
2240         devmode.dmFields |= DM_DISPLAYFREQUENCY;
2241     }
2242
2243     /* Only change the mode if necessary */
2244     if( (This->ddraw_width == pMode->Width) &&
2245         (This->ddraw_height == pMode->Height) &&
2246         (This->ddraw_format == pMode->Format) &&
2247         (pMode->RefreshRate == 0) ) {
2248         return WINED3D_OK;
2249     }
2250
2251     ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2252     if (ret != DISP_CHANGE_SUCCESSFUL) {
2253         if(devmode.dmDisplayFrequency != 0) {
2254             WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2255             devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2256             devmode.dmDisplayFrequency = 0;
2257             ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2258         }
2259         if(ret != DISP_CHANGE_SUCCESSFUL) {
2260             return WINED3DERR_NOTAVAILABLE;
2261         }
2262     }
2263
2264     /* Store the new values */
2265     This->ddraw_width = pMode->Width;
2266     This->ddraw_height = pMode->Height;
2267     This->ddraw_format = pMode->Format;
2268
2269     /* Only do this with a window of course */
2270     if(This->ddraw_window)
2271       MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2272
2273     /* And finally clip mouse to our screen */
2274     SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2275     ClipCursor(&clip_rc);
2276
2277     return WINED3D_OK;
2278 }
2279
2280 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2281    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2282    *ppD3D= This->wineD3D;
2283    TRACE("(%p) : wineD3D returning %p\n", This,  *ppD3D);
2284    IWineD3D_AddRef(*ppD3D);
2285    return WINED3D_OK;
2286 }
2287
2288 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2289     /** NOTE: There's a probably  a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2290     * into the video ram as possible and seeing how many fit
2291     * you can also get the correct initial value from nvidia and ATI's driver via X
2292     * texture memory is video memory + AGP memory
2293     *******************/
2294     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2295     static BOOL showfixmes = TRUE;
2296     if (showfixmes) {
2297         FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2298          (wined3d_settings.emulated_textureram/(1024*1024)),
2299          ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2300          showfixmes = FALSE;
2301     }
2302     TRACE("(%p) : simulating %dMB, returning %dMB left\n",  This,
2303          (wined3d_settings.emulated_textureram/(1024*1024)),
2304          ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2305     /* return simulated texture memory left */
2306     return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2307 }
2308
2309
2310
2311 /*****
2312  * Get / Set FVF
2313  *****/
2314 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2315     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316
2317     /* Update the current state block */
2318     This->updateStateBlock->changed.fvf      = TRUE;
2319
2320     if(This->updateStateBlock->fvf == fvf) {
2321         TRACE("Application is setting the old fvf over, nothing to do\n");
2322         return WINED3D_OK;
2323     }
2324
2325     This->updateStateBlock->fvf              = fvf;
2326     TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2327     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2328     return WINED3D_OK;
2329 }
2330
2331
2332 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2333     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334     TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2335     *pfvf = This->stateBlock->fvf;
2336     return WINED3D_OK;
2337 }
2338
2339 /*****
2340  * Get / Set Stream Source
2341  *****/
2342 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2343         IWineD3DDeviceImpl       *This = (IWineD3DDeviceImpl *)iface;
2344     IWineD3DVertexBuffer     *oldSrc;
2345
2346     if (StreamNumber >= MAX_STREAMS) {
2347         WARN("Stream out of range %d\n", StreamNumber);
2348         return WINED3DERR_INVALIDCALL;
2349     }
2350
2351     oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2352     TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2353
2354     This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2355
2356     if(oldSrc == pStreamData &&
2357        This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2358        This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2359        TRACE("Application is setting the old values over, nothing to do\n");
2360        return WINED3D_OK;
2361     }
2362
2363     This->updateStateBlock->streamSource[StreamNumber]         = pStreamData;
2364     if (pStreamData) {
2365         This->updateStateBlock->streamStride[StreamNumber]     = Stride;
2366         This->updateStateBlock->streamOffset[StreamNumber]     = OffsetInBytes;
2367     }
2368
2369     /* Handle recording of state blocks */
2370     if (This->isRecordingState) {
2371         TRACE("Recording... not performing anything\n");
2372         if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2373         if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2374         return WINED3D_OK;
2375     }
2376
2377     /* Need to do a getParent and pass the reffs up */
2378     /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2379     which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2380     so for now, just count internally   */
2381     if (pStreamData != NULL) {
2382         IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2383         InterlockedIncrement(&vbImpl->bindCount);
2384         IWineD3DVertexBuffer_AddRef(pStreamData);
2385     }
2386     if (oldSrc != NULL) {
2387         InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2388         IWineD3DVertexBuffer_Release(oldSrc);
2389     }
2390
2391     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2392
2393     return WINED3D_OK;
2394 }
2395
2396 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2397     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398
2399     TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2400            This->stateBlock->streamSource[StreamNumber],
2401            This->stateBlock->streamOffset[StreamNumber],
2402            This->stateBlock->streamStride[StreamNumber]);
2403
2404     if (StreamNumber >= MAX_STREAMS) {
2405         WARN("Stream out of range %d\n", StreamNumber);
2406         return WINED3DERR_INVALIDCALL;
2407     }
2408     *pStream = This->stateBlock->streamSource[StreamNumber];
2409     *pStride = This->stateBlock->streamStride[StreamNumber];
2410     if (pOffset) {
2411         *pOffset = This->stateBlock->streamOffset[StreamNumber];
2412     }
2413
2414     if (*pStream != NULL) {
2415         IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2416     }
2417     return WINED3D_OK;
2418 }
2419
2420 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT Divider) {
2421     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2422     UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2423     UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2424
2425     TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2426     This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA  | WINED3DSTREAMSOURCE_INDEXEDDATA );
2427
2428     This->updateStateBlock->changed.streamFreq[StreamNumber]  = TRUE;
2429     This->updateStateBlock->streamFreq[StreamNumber]          = Divider & 0x7FFFFF;
2430
2431     if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2432        This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2433         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2434     }
2435
2436     return WINED3D_OK;
2437 }
2438
2439 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT* Divider) {
2440     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2441
2442     TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2443     *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2444
2445     TRACE("(%p) : returning %d\n", This, *Divider);
2446
2447     return WINED3D_OK;
2448 }
2449
2450 /*****
2451  * Get / Set & Multiply Transform
2452  *****/
2453 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2454     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455
2456     /* Most of this routine, comments included copied from ddraw tree initially: */
2457     TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2458
2459     /* Handle recording of state blocks */
2460     if (This->isRecordingState) {
2461         TRACE("Recording... not performing anything\n");
2462         This->updateStateBlock->changed.transform[d3dts] = TRUE;
2463         memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2464         return WINED3D_OK;
2465     }
2466
2467     /*
2468      * If the new matrix is the same as the current one,
2469      * we cut off any further processing. this seems to be a reasonable
2470      * optimization because as was noticed, some apps (warcraft3 for example)
2471      * tend towards setting the same matrix repeatedly for some reason.
2472      *
2473      * From here on we assume that the new matrix is different, wherever it matters.
2474      */
2475     if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2476         TRACE("The app is setting the same matrix over again\n");
2477         return WINED3D_OK;
2478     } else {
2479         conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2480     }
2481
2482     /*
2483        ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2484        where ViewMat = Camera space, WorldMat = world space.
2485
2486        In OpenGL, camera and world space is combined into GL_MODELVIEW
2487        matrix.  The Projection matrix stay projection matrix.
2488      */
2489
2490     /* Capture the times we can just ignore the change for now */
2491     if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2492         This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2493         /* Handled by the state manager */
2494     }
2495
2496     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2497     return WINED3D_OK;
2498
2499 }
2500 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2501     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2502     TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2503     memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2504     return WINED3D_OK;
2505 }
2506
2507 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2508     WINED3DMATRIX *mat = NULL;
2509     WINED3DMATRIX temp;
2510
2511     /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2512      * below means it will be recorded in a state block change, but it
2513      * works regardless where it is recorded.
2514      * If this is found to be wrong, change to StateBlock.
2515      */
2516     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517     TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2518
2519     if (State < HIGHEST_TRANSFORMSTATE)
2520     {
2521         mat = &This->updateStateBlock->transforms[State];
2522     } else {
2523         FIXME("Unhandled transform state!!\n");
2524     }
2525
2526     multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2527
2528     /* Apply change via set transform - will reapply to eg. lights this way */
2529     return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2530 }
2531
2532 /*****
2533  * Get / Set Light
2534  *****/
2535 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2536    you can reference any indexes you want as long as that number max are enabled at any
2537    one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2538    However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2539    but when recording, just build a chain pretty much of commands to be replayed.                  */
2540
2541 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2542     float rho;
2543     PLIGHTINFOEL *object = NULL;
2544     UINT Hi = LIGHTMAP_HASHFUNC(Index);
2545     struct list *e;
2546
2547     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548     TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2549
2550     /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2551      * the gl driver.
2552      */
2553     if(!pLight) {
2554         WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2555         return WINED3DERR_INVALIDCALL;
2556     }
2557
2558     switch(pLight->Type) {
2559         case WINED3DLIGHT_POINT:
2560         case WINED3DLIGHT_SPOT:
2561         case WINED3DLIGHT_PARALLELPOINT:
2562         case WINED3DLIGHT_GLSPOT:
2563             /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2564              * most wanted
2565              */
2566             if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2567                 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2568                 return WINED3DERR_INVALIDCALL;
2569             }
2570             break;
2571
2572         case WINED3DLIGHT_DIRECTIONAL:
2573             /* Ignores attenuation */
2574             break;
2575
2576         default:
2577         WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2578         return WINED3DERR_INVALIDCALL;
2579     }
2580
2581     LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2582         object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2583         if(object->OriginalIndex == Index) break;
2584         object = NULL;
2585     }
2586
2587     if(!object) {
2588         TRACE("Adding new light\n");
2589         object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2590         if(!object) {
2591             ERR("Out of memory error when allocating a light\n");
2592             return E_OUTOFMEMORY;
2593         }
2594         list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2595         object->glIndex = -1;
2596         object->OriginalIndex = Index;
2597         object->changed = TRUE;
2598     }
2599
2600     /* Initialize the object */
2601     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,
2602           pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2603           pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2604           pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2605     TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2606           pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2607     TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2608
2609     /* Save away the information */
2610     memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2611
2612     switch (pLight->Type) {
2613     case WINED3DLIGHT_POINT:
2614         /* Position */
2615         object->lightPosn[0] = pLight->Position.x;
2616         object->lightPosn[1] = pLight->Position.y;
2617         object->lightPosn[2] = pLight->Position.z;
2618         object->lightPosn[3] = 1.0f;
2619         object->cutoff = 180.0f;
2620         /* FIXME: Range */
2621         break;
2622
2623     case WINED3DLIGHT_DIRECTIONAL:
2624         /* Direction */
2625         object->lightPosn[0] = -pLight->Direction.x;
2626         object->lightPosn[1] = -pLight->Direction.y;
2627         object->lightPosn[2] = -pLight->Direction.z;
2628         object->lightPosn[3] = 0.0;
2629         object->exponent     = 0.0f;
2630         object->cutoff       = 180.0f;
2631         break;
2632
2633     case WINED3DLIGHT_SPOT:
2634         /* Position */
2635         object->lightPosn[0] = pLight->Position.x;
2636         object->lightPosn[1] = pLight->Position.y;
2637         object->lightPosn[2] = pLight->Position.z;
2638         object->lightPosn[3] = 1.0;
2639
2640         /* Direction */
2641         object->lightDirn[0] = pLight->Direction.x;
2642         object->lightDirn[1] = pLight->Direction.y;
2643         object->lightDirn[2] = pLight->Direction.z;
2644         object->lightDirn[3] = 1.0;
2645
2646         /*
2647          * opengl-ish and d3d-ish spot lights use too different models for the
2648          * light "intensity" as a function of the angle towards the main light direction,
2649          * so we only can approximate very roughly.
2650          * however spot lights are rather rarely used in games (if ever used at all).
2651          * furthermore if still used, probably nobody pays attention to such details.
2652          */
2653         if (pLight->Falloff == 0) {
2654             /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2655              * falloff resp. exponent parameter as an exponent, so the spot light lighting
2656              * will always be 1.0 for both of them, and we don't have to care for the
2657              * rest of the rather complex calculation
2658              */
2659             object->exponent = 0;
2660         } else {
2661             rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2662             if (rho < 0.0001) rho = 0.0001f;
2663             object->exponent = -0.3/log(cos(rho/2));
2664         }
2665         if (object->exponent > 128.0) {
2666                 object->exponent = 128.0;
2667         }
2668         object->cutoff = pLight->Phi*90/M_PI;
2669
2670         /* FIXME: Range */
2671         break;
2672
2673     default:
2674         FIXME("Unrecognized light type %d\n", pLight->Type);
2675     }
2676
2677     /* Update the live definitions if the light is currently assigned a glIndex */
2678     if (object->glIndex != -1 && !This->isRecordingState) {
2679         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2680     }
2681     return WINED3D_OK;
2682 }
2683
2684 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2685     PLIGHTINFOEL *lightInfo = NULL;
2686     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687     DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2688     struct list *e;
2689     TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2690
2691     LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2692         lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2693         if(lightInfo->OriginalIndex == Index) break;
2694         lightInfo = NULL;
2695     }
2696
2697     if (lightInfo == NULL) {
2698         TRACE("Light information requested but light not defined\n");
2699         return WINED3DERR_INVALIDCALL;
2700     }
2701
2702     memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2703     return WINED3D_OK;
2704 }
2705
2706 /*****
2707  * Get / Set Light Enable
2708  *   (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2709  *****/
2710 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2711     PLIGHTINFOEL *lightInfo = NULL;
2712     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713     UINT Hi = LIGHTMAP_HASHFUNC(Index);
2714     struct list *e;
2715     TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2716
2717     /* Tests show true = 128...not clear why */
2718     Enable = Enable? 128: 0;
2719
2720     LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2721         lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2722         if(lightInfo->OriginalIndex == Index) break;
2723         lightInfo = NULL;
2724     }
2725     TRACE("Found light: %p\n", lightInfo);
2726
2727     /* Special case - enabling an undefined light creates one with a strict set of parms! */
2728     if (lightInfo == NULL) {
2729
2730         TRACE("Light enabled requested but light not defined, so defining one!\n");
2731         IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2732
2733         /* Search for it again! Should be fairly quick as near head of list */
2734         LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2735             lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2736             if(lightInfo->OriginalIndex == Index) break;
2737             lightInfo = NULL;
2738         }
2739         if (lightInfo == NULL) {
2740             FIXME("Adding default lights has failed dismally\n");
2741             return WINED3DERR_INVALIDCALL;
2742         }
2743     }
2744
2745     lightInfo->enabledChanged = TRUE;
2746     if(!Enable) {
2747         if(lightInfo->glIndex != -1) {
2748             if(!This->isRecordingState) {
2749                 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2750             }
2751
2752             This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2753             lightInfo->glIndex = -1;
2754         } else {
2755             TRACE("Light already disabled, nothing to do\n");
2756         }
2757     } else {
2758         if (lightInfo->glIndex != -1) {
2759             /* nop */
2760             TRACE("Nothing to do as light was enabled\n");
2761         } else {
2762             int i;
2763             /* Find a free gl light */
2764             for(i = 0; i < This->maxConcurrentLights; i++) {
2765                 if(This->stateBlock->activeLights[i] == NULL) {
2766                     This->stateBlock->activeLights[i] = lightInfo;
2767                     lightInfo->glIndex = i;
2768                     break;
2769                 }
2770             }
2771             if(lightInfo->glIndex == -1) {
2772                 ERR("Too many concurrently active lights\n");
2773                 return WINED3DERR_INVALIDCALL;
2774             }
2775
2776             /* i == lightInfo->glIndex */
2777             if(!This->isRecordingState) {
2778                 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2779             }
2780         }
2781     }
2782
2783     return WINED3D_OK;
2784 }
2785
2786 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2787
2788     PLIGHTINFOEL *lightInfo = NULL;
2789     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2790     struct list *e;
2791     UINT Hi = LIGHTMAP_HASHFUNC(Index);
2792     TRACE("(%p) : for idx(%d)\n", This, Index);
2793
2794     LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2795         lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2796         if(lightInfo->OriginalIndex == Index) break;
2797         lightInfo = NULL;
2798     }
2799
2800     if (lightInfo == NULL) {
2801         TRACE("Light enabled state requested but light not defined\n");
2802         return WINED3DERR_INVALIDCALL;
2803     }
2804     /* true is 128 according to SetLightEnable */
2805     *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2806     return WINED3D_OK;
2807 }
2808
2809 /*****
2810  * Get / Set Clip Planes
2811  *****/
2812 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2813     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814     TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2815
2816     /* Validate Index */
2817     if (Index >= GL_LIMITS(clipplanes)) {
2818         TRACE("Application has requested clipplane this device doesn't support\n");
2819         return WINED3DERR_INVALIDCALL;
2820     }
2821
2822     This->updateStateBlock->changed.clipplane[Index] = TRUE;
2823
2824     if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2825        This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2826        This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2827        This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2828         TRACE("Application is setting old values over, nothing to do\n");
2829         return WINED3D_OK;
2830     }
2831
2832     This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2833     This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2834     This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2835     This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2836
2837     /* Handle recording of state blocks */
2838     if (This->isRecordingState) {
2839         TRACE("Recording... not performing anything\n");
2840         return WINED3D_OK;
2841     }
2842
2843     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2844
2845     return WINED3D_OK;
2846 }
2847
2848 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2849     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850     TRACE("(%p) : for idx %d\n", This, Index);
2851
2852     /* Validate Index */
2853     if (Index >= GL_LIMITS(clipplanes)) {
2854         TRACE("Application has requested clipplane this device doesn't support\n");
2855         return WINED3DERR_INVALIDCALL;
2856     }
2857
2858     pPlane[0] = This->stateBlock->clipplane[Index][0];
2859     pPlane[1] = This->stateBlock->clipplane[Index][1];
2860     pPlane[2] = This->stateBlock->clipplane[Index][2];
2861     pPlane[3] = This->stateBlock->clipplane[Index][3];
2862     return WINED3D_OK;
2863 }
2864
2865 /*****
2866  * Get / Set Clip Plane Status
2867  *   WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2868  *****/
2869 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2870     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871     FIXME("(%p) : stub\n", This);
2872     if (NULL == pClipStatus) {
2873       return WINED3DERR_INVALIDCALL;
2874     }
2875     This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2876     This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2877     return WINED3D_OK;
2878 }
2879
2880 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2881     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882     FIXME("(%p) : stub\n", This);
2883     if (NULL == pClipStatus) {
2884       return WINED3DERR_INVALIDCALL;
2885     }
2886     pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2887     pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2888     return WINED3D_OK;
2889 }
2890
2891 /*****
2892  * Get / Set Material
2893  *****/
2894 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2895     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896
2897     This->updateStateBlock->changed.material = TRUE;
2898     memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2899
2900     /* Handle recording of state blocks */
2901     if (This->isRecordingState) {
2902         TRACE("Recording... not performing anything\n");
2903         return WINED3D_OK;
2904     }
2905
2906     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2907     return WINED3D_OK;
2908 }
2909
2910 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2911     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912     memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2913     TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2914         pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2915     TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2916         pMaterial->Ambient.b, pMaterial->Ambient.a);
2917     TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2918         pMaterial->Specular.b, pMaterial->Specular.a);
2919     TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2920         pMaterial->Emissive.b, pMaterial->Emissive.a);
2921     TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2922
2923     return WINED3D_OK;
2924 }
2925
2926 /*****
2927  * Get / Set Indices
2928  *****/
2929 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2930     IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;
2931     IWineD3DIndexBuffer *oldIdxs;
2932
2933     TRACE("(%p) : Setting to %p\n", This, pIndexData);
2934     oldIdxs = This->updateStateBlock->pIndexData;
2935
2936     This->updateStateBlock->changed.indices = TRUE;
2937     This->updateStateBlock->pIndexData = pIndexData;
2938
2939     /* Handle recording of state blocks */
2940     if (This->isRecordingState) {
2941         TRACE("Recording... not performing anything\n");
2942         if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2943         if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2944         return WINED3D_OK;
2945     }
2946
2947     if(oldIdxs != pIndexData) {
2948         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2949         if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2950         if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2951     }
2952     return WINED3D_OK;
2953 }
2954
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2956     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957
2958     *ppIndexData = This->stateBlock->pIndexData;
2959
2960     /* up ref count on ppindexdata */
2961     if (*ppIndexData) {
2962         IWineD3DIndexBuffer_AddRef(*ppIndexData);
2963         TRACE("(%p) index data set to %p\n", This, ppIndexData);
2964     }else{
2965         TRACE("(%p) No index data set\n", This);
2966     }
2967     TRACE("Returning %p\n", *ppIndexData);
2968
2969     return WINED3D_OK;
2970 }
2971
2972 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2973 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2974     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975     TRACE("(%p)->(%d)\n", This, BaseIndex);
2976
2977     if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2978         TRACE("Application is setting the old value over, nothing to do\n");
2979         return WINED3D_OK;
2980     }
2981
2982     This->updateStateBlock->baseVertexIndex = BaseIndex;
2983
2984     if (This->isRecordingState) {
2985         TRACE("Recording... not performing anything\n");
2986         return WINED3D_OK;
2987     }
2988     /* The base vertex index affects the stream sources */
2989     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2990     return WINED3D_OK;
2991 }
2992
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2994     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995     TRACE("(%p) : base_index %p\n", This, base_index);
2996
2997     *base_index = This->stateBlock->baseVertexIndex;
2998
2999     TRACE("Returning %u\n", *base_index);
3000
3001     return WINED3D_OK;
3002 }
3003
3004 /*****
3005  * Get / Set Viewports
3006  *****/
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3008     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3009
3010     TRACE("(%p)\n", This);
3011     This->updateStateBlock->changed.viewport = TRUE;
3012     memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3013
3014     /* Handle recording of state blocks */
3015     if (This->isRecordingState) {
3016         TRACE("Recording... not performing anything\n");
3017         return WINED3D_OK;
3018     }
3019
3020     TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3021           pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3022
3023     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3024     return WINED3D_OK;
3025
3026 }
3027
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3029     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030     TRACE("(%p)\n", This);
3031     memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3032     return WINED3D_OK;
3033 }
3034
3035 /*****
3036  * Get / Set Render States
3037  * TODO: Verify against dx9 definitions
3038  *****/
3039 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3040
3041     IWineD3DDeviceImpl  *This     = (IWineD3DDeviceImpl *)iface;
3042     DWORD oldValue = This->stateBlock->renderState[State];
3043
3044     TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3045
3046     This->updateStateBlock->changed.renderState[State] = TRUE;
3047     This->updateStateBlock->renderState[State] = Value;
3048
3049     /* Handle recording of state blocks */
3050     if (This->isRecordingState) {
3051         TRACE("Recording... not performing anything\n");
3052         return WINED3D_OK;
3053     }
3054
3055     /* Compared here and not before the assignment to allow proper stateblock recording */
3056     if(Value == oldValue) {
3057         TRACE("Application is setting the old value over, nothing to do\n");
3058     } else {
3059         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3060     }
3061
3062     return WINED3D_OK;
3063 }
3064
3065 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3066     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067     TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3068     *pValue = This->stateBlock->renderState[State];
3069     return WINED3D_OK;
3070 }
3071
3072 /*****
3073  * Get / Set Sampler States
3074  * TODO: Verify against dx9 definitions
3075  *****/
3076
3077 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3078     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079     DWORD oldValue;
3080
3081     TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3082             This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3083
3084     if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3085         Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3086     }
3087
3088     /**
3089     * SetSampler is designed to allow for more than the standard up to 8 textures
3090     *  and Geforce has stopped supporting more than 6 standard textures in openGL.
3091     * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3092     *
3093     * http://developer.nvidia.com/object/General_FAQ.html#t6
3094     *
3095     * There are two new settings for GForce
3096     * the sampler one:
3097     * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3098     * and the texture one:
3099     * GL_MAX_TEXTURE_COORDS_ARB.
3100     * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3101      ******************/
3102
3103     oldValue = This->stateBlock->samplerState[Sampler][Type];
3104     This->updateStateBlock->samplerState[Sampler][Type]         = Value;
3105     This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3106
3107     /* Handle recording of state blocks */
3108     if (This->isRecordingState) {
3109         TRACE("Recording... not performing anything\n");
3110         return WINED3D_OK;
3111     }
3112
3113     if(oldValue == Value) {
3114         TRACE("Application is setting the old value over, nothing to do\n");
3115         return WINED3D_OK;
3116     }
3117
3118     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3119
3120     return WINED3D_OK;
3121 }
3122
3123 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3124     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125
3126     TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3127             This, Sampler, debug_d3dsamplerstate(Type), Type);
3128
3129     if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3130         Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3131     }
3132
3133     *Value = This->stateBlock->samplerState[Sampler][Type];
3134     TRACE("(%p) : Returning %#x\n", This, *Value);
3135
3136     return WINED3D_OK;
3137 }
3138
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3140     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141
3142     This->updateStateBlock->changed.scissorRect = TRUE;
3143     if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3144         TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3145         return WINED3D_OK;
3146     }
3147     CopyRect(&This->updateStateBlock->scissorRect, pRect);
3148
3149     if(This->isRecordingState) {
3150         TRACE("Recording... not performing anything\n");
3151         return WINED3D_OK;
3152     }
3153
3154     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3155
3156     return WINED3D_OK;
3157 }
3158
3159 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3160     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161
3162     memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3163     TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3164     return WINED3D_OK;
3165 }
3166
3167 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3168     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3169     IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3170
3171     TRACE("(%p) : pDecl=%p\n", This, pDecl);
3172
3173     This->updateStateBlock->vertexDecl = pDecl;
3174     This->updateStateBlock->changed.vertexDecl = TRUE;
3175
3176     if (This->isRecordingState) {
3177         TRACE("Recording... not performing anything\n");
3178         return WINED3D_OK;
3179     } else if(pDecl == oldDecl) {
3180         /* Checked after the assignment to allow proper stateblock recording */
3181         TRACE("Application is setting the old declaration over, nothing to do\n");
3182         return WINED3D_OK;
3183     }
3184
3185     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3186     return WINED3D_OK;
3187 }
3188
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3190     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191
3192     TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3193
3194     *ppDecl = This->stateBlock->vertexDecl;
3195     if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3196     return WINED3D_OK;
3197 }
3198
3199 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3200     IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
3201     IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3202
3203     This->updateStateBlock->vertexShader         = pShader;
3204     This->updateStateBlock->changed.vertexShader = TRUE;
3205
3206     if (This->isRecordingState) {
3207         if(pShader) IWineD3DVertexShader_AddRef(pShader);
3208         if(oldShader) IWineD3DVertexShader_Release(oldShader);
3209         TRACE("Recording... not performing anything\n");
3210         return WINED3D_OK;
3211     } else if(oldShader == pShader) {
3212         /* Checked here to allow proper stateblock recording */
3213         TRACE("App is setting the old shader over, nothing to do\n");
3214         return WINED3D_OK;
3215     }
3216
3217     TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3218     if(pShader) IWineD3DVertexShader_AddRef(pShader);
3219     if(oldShader) IWineD3DVertexShader_Release(oldShader);
3220
3221     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3222
3223     return WINED3D_OK;
3224 }
3225
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3227     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228
3229     if (NULL == ppShader) {
3230         return WINED3DERR_INVALIDCALL;
3231     }
3232     *ppShader = This->stateBlock->vertexShader;
3233     if( NULL != *ppShader)
3234         IWineD3DVertexShader_AddRef(*ppShader);
3235
3236     TRACE("(%p) : returning %p\n", This, *ppShader);
3237     return WINED3D_OK;
3238 }
3239
3240 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3241     IWineD3DDevice *iface,
3242     UINT start,
3243     CONST BOOL *srcData,
3244     UINT count) {
3245
3246     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247     int i, cnt = min(count, MAX_CONST_B - start);
3248
3249     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3250             iface, srcData, start, count);
3251
3252     if (srcData == NULL || cnt < 0)
3253         return WINED3DERR_INVALIDCALL;
3254
3255     memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3256     for (i = 0; i < cnt; i++)
3257         TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3258
3259     for (i = start; i < cnt + start; ++i) {
3260         This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3261     }
3262
3263     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3264
3265     return WINED3D_OK;
3266 }
3267
3268 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3269     IWineD3DDevice *iface,
3270     UINT start,
3271     BOOL *dstData,
3272     UINT count) {
3273
3274     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275     int cnt = min(count, MAX_CONST_B - start);
3276
3277     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3278             iface, dstData, start, count);
3279
3280     if (dstData == NULL || cnt < 0)
3281         return WINED3DERR_INVALIDCALL;
3282
3283     memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3284     return WINED3D_OK;
3285 }
3286
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3288     IWineD3DDevice *iface,
3289     UINT start,
3290     CONST int *srcData,
3291     UINT count) {
3292
3293     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294     int i, cnt = min(count, MAX_CONST_I - start);
3295
3296     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3297             iface, srcData, start, count);
3298
3299     if (srcData == NULL || cnt < 0)
3300         return WINED3DERR_INVALIDCALL;
3301
3302     memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3303     for (i = 0; i < cnt; i++)
3304         TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3305            srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3306
3307     for (i = start; i < cnt + start; ++i) {
3308         This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3309     }
3310
3311     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3312
3313     return WINED3D_OK;
3314 }
3315
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3317     IWineD3DDevice *iface,
3318     UINT start,
3319     int *dstData,
3320     UINT count) {
3321
3322     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323     int cnt = min(count, MAX_CONST_I - start);
3324
3325     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3326             iface, dstData, start, count);
3327
3328     if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3329         return WINED3DERR_INVALIDCALL;
3330
3331     memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3332     return WINED3D_OK;
3333 }
3334
3335 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3336     IWineD3DDevice *iface,
3337     UINT start,
3338     CONST float *srcData,
3339     UINT count) {
3340
3341     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3342     int i;
3343
3344     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3345             iface, srcData, start, count);
3346
3347     /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3348     if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3349         return WINED3DERR_INVALIDCALL;
3350
3351     memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3352     if(TRACE_ON(d3d)) {
3353         for (i = 0; i < count; i++)
3354             TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3355                 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3356     }
3357
3358     for (i = start; i < count + start; ++i) {
3359         if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3360             constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3361             if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3362                 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3363                 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3364             }
3365             ptr->idx[ptr->count++] = i;
3366             This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3367         }
3368     }
3369
3370     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3371
3372     return WINED3D_OK;
3373 }
3374
3375 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3376     IWineD3DDevice *iface,
3377     UINT start,
3378     float *dstData,
3379     UINT count) {
3380
3381     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382     int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3383
3384     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3385             iface, dstData, start, count);
3386
3387     if (dstData == NULL || cnt < 0)
3388         return WINED3DERR_INVALIDCALL;
3389
3390     memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3391     return WINED3D_OK;
3392 }
3393
3394 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3395     DWORD i;
3396     for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3397         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3398     }
3399 }
3400
3401 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3402     int i = This->rev_tex_unit_map[unit];
3403     int j = This->texUnitMap[stage];
3404
3405     This->texUnitMap[stage] = unit;
3406     if (i != -1 && i != stage) {
3407         This->texUnitMap[i] = -1;
3408     }
3409
3410     This->rev_tex_unit_map[unit] = stage;
3411     if (j != -1 && j != unit) {
3412         This->rev_tex_unit_map[j] = -1;
3413     }
3414 }
3415
3416 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3417     int i;
3418
3419     for (i = 0; i < MAX_TEXTURES; ++i) {
3420         WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3421         WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3422         DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3423         DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3424         DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3425         DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3426         DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3427         DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3428
3429         if (color_op == WINED3DTOP_DISABLE) {
3430             /* Not used, and disable higher stages */
3431             while (i < MAX_TEXTURES) {
3432                 This->fixed_function_usage_map[i] = FALSE;
3433                 ++i;
3434             }
3435             break;
3436         }
3437
3438         if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3439                 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3440                 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3441                 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3442                 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3443                 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3444             This->fixed_function_usage_map[i] = TRUE;
3445         } else {
3446             This->fixed_function_usage_map[i] = FALSE;
3447         }
3448
3449         if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3450             This->fixed_function_usage_map[i+1] = TRUE;
3451         }
3452     }
3453 }
3454
3455 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3456     int i, tex;
3457
3458     device_update_fixed_function_usage_map(This);
3459
3460     if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3461         for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3462             if (!This->fixed_function_usage_map[i]) continue;
3463
3464             if (This->texUnitMap[i] != i) {
3465                 device_map_stage(This, i, i);
3466                 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3467                 markTextureStagesDirty(This, i);
3468             }
3469         }
3470         return;
3471     }
3472
3473     /* Now work out the mapping */
3474     tex = 0;
3475     for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3476         if (!This->fixed_function_usage_map[i]) continue;
3477
3478         if (This->texUnitMap[i] != tex) {
3479             device_map_stage(This, i, tex);
3480             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3481             markTextureStagesDirty(This, i);
3482         }
3483
3484         ++tex;
3485     }
3486 }
3487
3488 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3489     DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3490     int i;
3491
3492     for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3493         if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3494             device_map_stage(This, i, i);
3495             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3496             if (i < MAX_TEXTURES) {
3497                 markTextureStagesDirty(This, i);
3498             }
3499         }
3500     }
3501 }
3502
3503 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3504     int current_mapping = This->rev_tex_unit_map[unit];
3505
3506     if (current_mapping == -1) {
3507         /* Not currently used */
3508         return TRUE;
3509     }
3510
3511     if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3512         /* Used by a fragment sampler */
3513
3514         if (!pshader_sampler_tokens) {
3515             /* No pixel shader, check fixed function */
3516             return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3517         }
3518
3519         /* Pixel shader, check the shader's sampler map */
3520         return !pshader_sampler_tokens[current_mapping];
3521     }
3522
3523     /* Used by a vertex sampler */
3524     return !vshader_sampler_tokens[current_mapping];
3525 }
3526
3527 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3528     DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3529     DWORD *pshader_sampler_tokens = NULL;
3530     int start = GL_LIMITS(combined_samplers) - 1;
3531     int i;
3532
3533     if (ps) {
3534         IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3535
3536         /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3537         IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3538         pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3539     }
3540
3541     for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3542         int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3543         if (vshader_sampler_tokens[i]) {
3544             if (This->texUnitMap[vsampler_idx] != -1) {
3545                 /* Already mapped somewhere */
3546                 continue;
3547             }
3548
3549             while (start >= 0) {
3550                 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3551                     device_map_stage(This, vsampler_idx, start);
3552                     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3553
3554                     --start;
3555                     break;
3556                 }
3557
3558                 --start;
3559             }
3560         }
3561     }
3562 }
3563
3564 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3565     BOOL vs = use_vs(This);
3566     BOOL ps = use_ps(This);
3567     /*
3568      * Rules are:
3569      * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3570      * that would be really messy and require shader recompilation
3571      * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3572      * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3573      */
3574     if (ps) {
3575         device_map_psamplers(This);
3576     } else {
3577         device_map_fixed_function_samplers(This);
3578     }
3579
3580     if (vs) {
3581         device_map_vsamplers(This, ps);
3582     }
3583 }
3584
3585 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3586     IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
3587     IWineD3DPixelShader *oldShader  = This->updateStateBlock->pixelShader;
3588     This->updateStateBlock->pixelShader         = pShader;
3589     This->updateStateBlock->changed.pixelShader = TRUE;
3590
3591     /* Handle recording of state blocks */
3592     if (This->isRecordingState) {
3593         TRACE("Recording... not performing anything\n");
3594     }
3595
3596     if (This->isRecordingState) {
3597         TRACE("Recording... not performing anything\n");
3598         if(pShader) IWineD3DPixelShader_AddRef(pShader);
3599         if(oldShader) IWineD3DPixelShader_Release(oldShader);
3600         return WINED3D_OK;
3601     }
3602
3603     if(pShader == oldShader) {
3604         TRACE("App is setting the old pixel shader over, nothing to do\n");
3605         return WINED3D_OK;
3606     }
3607
3608     if(pShader) IWineD3DPixelShader_AddRef(pShader);
3609     if(oldShader) IWineD3DPixelShader_Release(oldShader);
3610
3611     TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3612     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3613
3614     return WINED3D_OK;
3615 }
3616
3617 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3618     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619
3620     if (NULL == ppShader) {
3621         WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3622         return WINED3DERR_INVALIDCALL;
3623     }
3624
3625     *ppShader =  This->stateBlock->pixelShader;
3626     if (NULL != *ppShader) {
3627         IWineD3DPixelShader_AddRef(*ppShader);
3628     }
3629     TRACE("(%p) : returning %p\n", This, *ppShader);
3630     return WINED3D_OK;
3631 }
3632
3633 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3634     IWineD3DDevice *iface,
3635     UINT start,
3636     CONST BOOL *srcData,
3637     UINT count) {
3638
3639     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640     int i, cnt = min(count, MAX_CONST_B - start);
3641
3642     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3643             iface, srcData, start, count);
3644
3645     if (srcData == NULL || cnt < 0)
3646         return WINED3DERR_INVALIDCALL;
3647
3648     memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3649     for (i = 0; i < cnt; i++)
3650         TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3651
3652     for (i = start; i < cnt + start; ++i) {
3653         This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3654     }
3655
3656     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3657
3658     return WINED3D_OK;
3659 }
3660
3661 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3662     IWineD3DDevice *iface,
3663     UINT start,
3664     BOOL *dstData,
3665     UINT count) {
3666
3667     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3668     int cnt = min(count, MAX_CONST_B - start);
3669
3670     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3671             iface, dstData, start, count);
3672
3673     if (dstData == NULL || cnt < 0)
3674         return WINED3DERR_INVALIDCALL;
3675
3676     memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3677     return WINED3D_OK;
3678 }
3679
3680 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3681     IWineD3DDevice *iface,
3682     UINT start,
3683     CONST int *srcData,
3684     UINT count) {
3685
3686     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687     int i, cnt = min(count, MAX_CONST_I - start);
3688
3689     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3690             iface, srcData, start, count);
3691
3692     if (srcData == NULL || cnt < 0)
3693         return WINED3DERR_INVALIDCALL;
3694
3695     memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3696     for (i = 0; i < cnt; i++)
3697         TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3698            srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3699
3700     for (i = start; i < cnt + start; ++i) {
3701         This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3702     }
3703
3704     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3705
3706     return WINED3D_OK;
3707 }
3708
3709 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3710     IWineD3DDevice *iface,
3711     UINT start,
3712     int *dstData,
3713     UINT count) {
3714
3715     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3716     int cnt = min(count, MAX_CONST_I - start);
3717
3718     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3719             iface, dstData, start, count);
3720
3721     if (dstData == NULL || cnt < 0)
3722         return WINED3DERR_INVALIDCALL;
3723
3724     memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3725     return WINED3D_OK;
3726 }
3727
3728 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3729     IWineD3DDevice *iface,
3730     UINT start,
3731     CONST float *srcData,
3732     UINT count) {
3733
3734     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3735     int i;
3736
3737     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3738             iface, srcData, start, count);
3739
3740     /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3741     if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3742         return WINED3DERR_INVALIDCALL;
3743
3744     memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3745     if(TRACE_ON(d3d)) {
3746         for (i = 0; i < count; i++)
3747             TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3748                 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3749     }
3750
3751     for (i = start; i < count + start; ++i) {
3752         if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3753             constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3754             if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3755                 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3756                 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3757             }
3758             ptr->idx[ptr->count++] = i;
3759             This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3760         }
3761     }
3762
3763     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3764
3765     return WINED3D_OK;
3766 }
3767
3768 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3769     IWineD3DDevice *iface,
3770     UINT start,
3771     float *dstData,
3772     UINT count) {
3773
3774     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3775     int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3776
3777     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3778             iface, dstData, start, count);
3779
3780     if (dstData == NULL || cnt < 0)
3781         return WINED3DERR_INVALIDCALL;
3782
3783     memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3784     return WINED3D_OK;
3785 }
3786
3787 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3788 static HRESULT
3789 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3790     char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3791     unsigned int i;
3792     DWORD DestFVF = dest->fvf;
3793     WINED3DVIEWPORT vp;
3794     WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3795     BOOL doClip;
3796     int numTextures;
3797
3798     if (lpStrideData->u.s.normal.lpData) {
3799         WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3800     }
3801
3802     if (lpStrideData->u.s.position.lpData == NULL) {
3803         ERR("Source has no position mask\n");
3804         return WINED3DERR_INVALIDCALL;
3805     }
3806
3807     /* We might access VBOs from this code, so hold the lock */
3808     ENTER_GL();
3809
3810     if (dest->resource.allocatedMemory == NULL) {
3811         /* This may happen if we do direct locking into a vbo. Unlikely,
3812          * but theoretically possible(ddraw processvertices test)
3813          */
3814         dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3815         if(!dest->resource.allocatedMemory) {
3816             LEAVE_GL();
3817             ERR("Out of memory\n");
3818             return E_OUTOFMEMORY;
3819         }
3820         if(dest->vbo) {
3821             void *src;
3822             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3823             checkGLcall("glBindBufferARB");
3824             src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3825             if(src) {
3826                 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3827             }
3828             GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3829             checkGLcall("glUnmapBufferARB");
3830         }
3831     }
3832
3833     /* Get a pointer into the destination vbo(create one if none exists) and
3834      * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3835      */
3836     if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3837         CreateVBO(dest);
3838     }
3839
3840     if(dest->vbo) {
3841         unsigned char extrabytes = 0;
3842         /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3843          * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3844          * this may write 4 extra bytes beyond the area that should be written
3845          */
3846         if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3847         dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3848         if(!dest_conv_addr) {
3849             ERR("Out of memory\n");
3850             /* Continue without storing converted vertices */
3851         }
3852         dest_conv = dest_conv_addr;
3853     }
3854
3855     /* Should I clip?
3856      * a) WINED3DRS_CLIPPING is enabled
3857      * b) WINED3DVOP_CLIP is passed
3858      */
3859     if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3860         static BOOL warned = FALSE;
3861         /*
3862          * The clipping code is not quite correct. Some things need
3863          * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3864          * so disable clipping for now.
3865          * (The graphics in Half-Life are broken, and my processvertices
3866          *  test crashes with IDirect3DDevice3)
3867         doClip = TRUE;
3868          */
3869         doClip = FALSE;
3870         if(!warned) {
3871            warned = TRUE;
3872            FIXME("Clipping is broken and disabled for now\n");
3873         }
3874     } else doClip = FALSE;
3875     dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3876
3877     IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3878                                  WINED3DTS_VIEW,
3879                                  &view_mat);
3880     IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3881                                  WINED3DTS_PROJECTION,
3882                                  &proj_mat);
3883     IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3884                                  WINED3DTS_WORLDMATRIX(0),
3885                                  &world_mat);
3886
3887     TRACE("View mat:\n");
3888     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);
3889     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);
3890     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);
3891     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);
3892
3893     TRACE("Proj mat:\n");
3894     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);
3895     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);
3896     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);
3897     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);
3898
3899     TRACE("World mat:\n");
3900     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);
3901     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);
3902     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);
3903     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);
3904
3905     /* Get the viewport */
3906     IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3907     TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3908           vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3909
3910     multiply_matrix(&mat,&view_mat,&world_mat);
3911     multiply_matrix(&mat,&proj_mat,&mat);
3912
3913     numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3914
3915     for (i = 0; i < dwCount; i+= 1) {
3916         unsigned int tex_index;
3917
3918         if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3919              ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3920             /* The position first */
3921             float *p =
3922               (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3923             float x, y, z, rhw;
3924             TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3925
3926             /* Multiplication with world, view and projection matrix */
3927             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);
3928             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);
3929             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);
3930             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);
3931
3932             TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3933
3934             /* WARNING: The following things are taken from d3d7 and were not yet checked
3935              * against d3d8 or d3d9!
3936              */
3937
3938             /* Clipping conditions: From
3939              * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3940              *
3941              * A vertex is clipped if it does not match the following requirements
3942              * -rhw < x <= rhw
3943              * -rhw < y <= rhw
3944              *    0 < z <= rhw
3945              *    0 < rhw ( Not in d3d7, but tested in d3d7)
3946              *
3947              * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3948              * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3949              *
3950              */
3951
3952             if( !doClip ||
3953                 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3954                   (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) && 
3955                   ( rhw > eps ) ) ) {
3956
3957                 /* "Normal" viewport transformation (not clipped)
3958                  * 1) The values are divided by rhw
3959                  * 2) The y axis is negative, so multiply it with -1
3960                  * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3961                  *    -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3962                  * 4) Multiply x with Width/2 and add Width/2
3963                  * 5) The same for the height
3964                  * 6) Add the viewpoint X and Y to the 2D coordinates and
3965                  *    The minimum Z value to z
3966                  * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3967                  *
3968                  * Well, basically it's simply a linear transformation into viewport
3969                  * coordinates
3970                  */
3971
3972                 x /= rhw;
3973                 y /= rhw;
3974                 z /= rhw;
3975
3976                 y *= -1;
3977
3978                 x *= vp.Width / 2;
3979                 y *= vp.Height / 2;
3980                 z *= vp.MaxZ - vp.MinZ;
3981
3982                 x += vp.Width / 2 + vp.X;
3983                 y += vp.Height / 2 + vp.Y;
3984                 z += vp.MinZ;
3985
3986                 rhw = 1 / rhw;
3987             } else {
3988                 /* That vertex got clipped
3989                  * Contrary to OpenGL it is not dropped completely, it just
3990                  * undergoes a different calculation.
3991                  */
3992                 TRACE("Vertex got clipped\n");
3993                 x += rhw;
3994                 y += rhw;
3995
3996                 x  /= 2;
3997                 y  /= 2;
3998
3999                 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4000                  * outside of the main vertex buffer memory. That needs some more
4001                  * investigation...
4002                  */
4003             }
4004
4005             TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4006
4007
4008             ( (float *) dest_ptr)[0] = x;
4009             ( (float *) dest_ptr)[1] = y;
4010             ( (float *) dest_ptr)[2] = z;
4011             ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4012
4013             dest_ptr += 3 * sizeof(float);
4014
4015             if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4016                 dest_ptr += sizeof(float);
4017             }
4018
4019             if(dest_conv) {
4020                 float w = 1 / rhw;
4021                 ( (float *) dest_conv)[0] = x * w;
4022                 ( (float *) dest_conv)[1] = y * w;
4023                 ( (float *) dest_conv)[2] = z * w;
4024                 ( (float *) dest_conv)[3] = w;
4025
4026                 dest_conv += 3 * sizeof(float);
4027
4028                 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4029                     dest_conv += sizeof(float);
4030                 }
4031             }
4032         }
4033         if (DestFVF & WINED3DFVF_PSIZE) {
4034             dest_ptr += sizeof(DWORD);
4035             if(dest_conv) dest_conv += sizeof(DWORD);
4036         }
4037         if (DestFVF & WINED3DFVF_NORMAL) {
4038             float *normal =
4039               (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4040             /* AFAIK this should go into the lighting information */
4041             FIXME("Didn't expect the destination to have a normal\n");
4042             copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4043             if(dest_conv) {
4044                 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4045             }
4046         }
4047
4048         if (DestFVF & WINED3DFVF_DIFFUSE) {
4049             DWORD *color_d = 
4050               (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4051             if(!color_d) {
4052                 static BOOL warned = FALSE;
4053
4054                 if(!warned) {
4055                     ERR("No diffuse color in source, but destination has one\n");
4056                     warned = TRUE;
4057                 }
4058
4059                 *( (DWORD *) dest_ptr) = 0xffffffff;
4060                 dest_ptr += sizeof(DWORD);
4061
4062                 if(dest_conv) {
4063                     *( (DWORD *) dest_conv) = 0xffffffff;
4064                     dest_conv += sizeof(DWORD);
4065                 }
4066             }
4067             else {
4068                 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4069                 if(dest_conv) {
4070                     *( (DWORD *) dest_conv)  = (*color_d & 0xff00ff00)      ; /* Alpha + green */
4071                     *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4072                     *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4073                     dest_conv += sizeof(DWORD);
4074                 }
4075             }
4076         }
4077
4078         if (DestFVF & WINED3DFVF_SPECULAR) { 
4079             /* What's the color value in the feedback buffer? */
4080             DWORD *color_s = 
4081               (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4082             if(!color_s) {
4083                 static BOOL warned = FALSE;
4084
4085                 if(!warned) {
4086                     ERR("No specular color in source, but destination has one\n");
4087                     warned = TRUE;
4088                 }
4089
4090                 *( (DWORD *) dest_ptr) = 0xFF000000;
4091                 dest_ptr += sizeof(DWORD);
4092
4093                 if(dest_conv) {
4094                     *( (DWORD *) dest_conv) = 0xFF000000;
4095                     dest_conv += sizeof(DWORD);
4096                 }
4097             }
4098             else {
4099                 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4100                 if(dest_conv) {
4101                     *( (DWORD *) dest_conv)  = (*color_s & 0xff00ff00)      ; /* Alpha + green */
4102                     *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4103                     *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4104                     dest_conv += sizeof(DWORD);
4105                 }
4106             }
4107         }
4108
4109         for (tex_index = 0; tex_index < numTextures; tex_index++) {
4110             float *tex_coord =
4111               (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) + 
4112                             i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4113             if(!tex_coord) {
4114                 ERR("No source texture, but destination requests one\n");
4115                 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4116                 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4117             }
4118             else {
4119                 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4120                 if(dest_conv) {
4121                     copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4122                 }
4123             }
4124         }
4125     }
4126
4127     if(dest_conv) {
4128         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4129         checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4130         GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4131                                       dwCount * get_flexible_vertex_size(DestFVF),
4132                                       dest_conv_addr));
4133         checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4134         HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4135     }
4136
4137     LEAVE_GL();
4138
4139     return WINED3D_OK;
4140 }
4141 #undef copy_and_next
4142
4143 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4144     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4145     WineDirect3DVertexStridedData strided;
4146     BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4147     TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4148
4149     if(pVertexDecl) {
4150         ERR("Output vertex declaration not implemented yet\n");
4151     }
4152
4153     /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4154      * and this call is quite performance critical, so don't call needlessly
4155      */
4156     if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4157         ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4158     }
4159
4160     /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4161      * control the streamIsUP flag, thus restore it afterwards.
4162      */
4163     This->stateBlock->streamIsUP = FALSE;
4164     memset(&strided, 0, sizeof(strided));
4165     primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4166     This->stateBlock->streamIsUP = streamWasUP;
4167
4168     if(vbo || SrcStartIndex) {
4169         unsigned int i;
4170         /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4171          * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4172          *
4173          * Also get the start index in, but only loop over all elements if there's something to add at all.
4174          */
4175 #define FIXSRC(type) \
4176         if(strided.u.s.type.VBO) { \
4177             IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4178             strided.u.s.type.VBO = 0; \
4179             strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4180             ENTER_GL(); \
4181             GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4182             vb->vbo = 0; \
4183             LEAVE_GL(); \
4184         } \
4185         if(strided.u.s.type.lpData) { \
4186             strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4187         }
4188         FIXSRC(position);
4189         FIXSRC(blendWeights);
4190         FIXSRC(blendMatrixIndices);
4191         FIXSRC(normal);
4192         FIXSRC(pSize);
4193         FIXSRC(diffuse);
4194         FIXSRC(specular);
4195         for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4196             FIXSRC(texCoords[i]);
4197         }
4198         FIXSRC(position2);
4199         FIXSRC(normal2);
4200         FIXSRC(tangent);
4201         FIXSRC(binormal);
4202         FIXSRC(tessFactor);
4203         FIXSRC(fog);
4204         FIXSRC(depth);
4205         FIXSRC(sample);
4206 #undef FIXSRC
4207     }
4208
4209     return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4210 }
4211
4212 /*****
4213  * Get / Set Texture Stage States
4214  * TODO: Verify against dx9 definitions
4215  *****/
4216 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4217     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4218     DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4219
4220     TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4221
4222     if (Stage >= MAX_TEXTURES) {
4223         WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4224         return WINED3D_OK;
4225     }
4226
4227     This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4228     This->updateStateBlock->textureState[Stage][Type]         = Value;
4229
4230     if (This->isRecordingState) {
4231         TRACE("Recording... not performing anything\n");
4232         return WINED3D_OK;
4233     }
4234
4235     /* Checked after the assignments to allow proper stateblock recording */
4236     if(oldValue == Value) {
4237         TRACE("App is setting the old value over, nothing to do\n");
4238         return WINED3D_OK;
4239     }
4240
4241     if(Stage > This->stateBlock->lowest_disabled_stage &&
4242        StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4243         /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4244          * Changes in other states are important on disabled stages too
4245          */
4246         return WINED3D_OK;
4247     }
4248
4249     if(Type == WINED3DTSS_COLOROP) {
4250         int i;
4251
4252         if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4253             /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4254              * they have to be disabled
4255              *
4256              * The current stage is dirtified below.
4257              */
4258             for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4259                 TRACE("Additionally dirtifying stage %d\n", i);
4260                 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4261             }
4262             This->stateBlock->lowest_disabled_stage = Stage;
4263             TRACE("New lowest disabled: %d\n", Stage);
4264         } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4265             /* Previously disabled stage enabled. Stages above it may need enabling
4266              * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4267              * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4268              *
4269              * Again stage Stage doesn't need to be dirtified here, it is handled below.
4270              */
4271
4272             for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4273                 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4274                     break;
4275                 }
4276                 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4277                 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4278             }
4279             This->stateBlock->lowest_disabled_stage = i;
4280             TRACE("New lowest disabled: %d\n", i);
4281         }
4282         if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4283             /* TODO: Built a stage -> texture unit mapping for register combiners */
4284         }
4285     }
4286
4287     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4288
4289     return WINED3D_OK;
4290 }
4291
4292 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4293     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4294     TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4295     *pValue = This->updateStateBlock->textureState[Stage][Type];
4296     return WINED3D_OK;
4297 }
4298
4299 /*****
4300  * Get / Set Texture
4301  *****/
4302 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4303     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4304     IWineD3DBaseTexture *oldTexture;
4305
4306     TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4307
4308     if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4309         Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4310     }
4311
4312     oldTexture = This->updateStateBlock->textures[Stage];
4313
4314     if(pTexture != NULL) {
4315         /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH; 
4316          */
4317         if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4318             WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4319             return WINED3DERR_INVALIDCALL;
4320         }
4321         This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4322     }
4323
4324     TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4325     TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4326
4327     This->updateStateBlock->changed.textures[Stage] = TRUE;
4328     TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4329     This->updateStateBlock->textures[Stage]         = pTexture;
4330
4331     /* Handle recording of state blocks */
4332     if (This->isRecordingState) {
4333         TRACE("Recording... not performing anything\n");
4334         return WINED3D_OK;
4335     }
4336
4337     if(oldTexture == pTexture) {
4338         TRACE("App is setting the same texture again, nothing to do\n");
4339         return WINED3D_OK;
4340     }
4341
4342     /** NOTE: MSDN says that setTexture increases the reference count,
4343     * and the the application must set the texture back to null (or have a leaky application),
4344     * This means we should pass the refcount up to the parent
4345      *******************************/
4346     if (NULL != This->updateStateBlock->textures[Stage]) {
4347         IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4348         ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4349
4350         IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4351         if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4352             /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4353              * so the COLOROP and ALPHAOP have to be dirtified.
4354              */
4355             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4356             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4357         }
4358         if(bindCount == 1) {
4359             new->baseTexture.sampler = Stage;
4360         }
4361         /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4362
4363     }
4364
4365     if (NULL != oldTexture) {
4366         IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4367         LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4368
4369         IWineD3DBaseTexture_Release(oldTexture);
4370         if(pTexture == NULL && Stage < MAX_TEXTURES) {
4371             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4372             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4373         }
4374
4375         if(bindCount && old->baseTexture.sampler == Stage) {
4376             int i;
4377             /* Have to do a search for the other sampler(s) where the texture is bound to
4378              * Shouldn't happen as long as apps bind a texture only to one stage
4379              */
4380             TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4381             for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4382                 if(This->updateStateBlock->textures[i] == oldTexture) {
4383                     old->baseTexture.sampler = i;
4384                     break;
4385                 }
4386             }
4387         }
4388     }
4389
4390     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4391
4392     return WINED3D_OK;
4393 }
4394
4395 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4396     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4397
4398     TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4399
4400     if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4401         Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4402     }
4403
4404     *ppTexture=This->stateBlock->textures[Stage];
4405     if (*ppTexture)
4406         IWineD3DBaseTexture_AddRef(*ppTexture);
4407
4408     TRACE("(%p) : Returning %p\n", This, *ppTexture);
4409
4410     return WINED3D_OK;
4411 }
4412
4413 /*****
4414  * Get Back Buffer
4415  *****/
4416 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4417                                                 IWineD3DSurface **ppBackBuffer) {
4418     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4419     IWineD3DSwapChain *swapChain;
4420     HRESULT hr;
4421
4422     TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4423
4424     hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, &swapChain);
4425     if (hr == WINED3D_OK) {
4426         hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4427             IWineD3DSwapChain_Release(swapChain);
4428     } else {
4429         *ppBackBuffer = NULL;
4430     }
4431     return hr;
4432 }
4433
4434 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4435     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436     WARN("(%p) : stub, calling idirect3d for now\n", This);
4437     return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4438 }
4439
4440 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4441     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442     IWineD3DSwapChain *swapChain;
4443     HRESULT hr;
4444
4445     if(iSwapChain > 0) {
4446         hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, (IWineD3DSwapChain **)&swapChain);
4447         if (hr == WINED3D_OK) {
4448             hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4449             IWineD3DSwapChain_Release(swapChain);
4450         } else {
4451             FIXME("(%p) Error getting display mode\n", This);
4452         }
4453     } else {
4454         /* Don't read the real display mode,
4455            but return the stored mode instead. X11 can't change the color
4456            depth, and some apps are pretty angry if they SetDisplayMode from
4457            24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4458
4459            Also don't relay to the swapchain because with ddraw it's possible
4460            that there isn't a swapchain at all */
4461         pMode->Width = This->ddraw_width;
4462         pMode->Height = This->ddraw_height;
4463         pMode->Format = This->ddraw_format;
4464         pMode->RefreshRate = 0;
4465         hr = WINED3D_OK;
4466     }
4467
4468     return hr;
4469 }
4470
4471 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4472     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473     TRACE("(%p)->(%p)\n", This, hWnd);
4474
4475     if(This->ddraw_fullscreen) {
4476         if(This->ddraw_window && This->ddraw_window != hWnd) {
4477             IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4478         }
4479         if(hWnd && This->ddraw_window != hWnd) {
4480             IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4481         }
4482     }
4483
4484     This->ddraw_window = hWnd;
4485     return WINED3D_OK;
4486 }
4487
4488 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4489     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490     TRACE("(%p)->(%p)\n", This, hWnd);
4491
4492     *hWnd = This->ddraw_window;
4493     return WINED3D_OK;
4494 }
4495
4496 /*****
4497  * Stateblock related functions
4498  *****/
4499
4500 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4501     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4502     IWineD3DStateBlockImpl *object;
4503     HRESULT temp_result;
4504     int i;
4505
4506     TRACE("(%p)\n", This);
4507     
4508     if (This->isRecordingState) {
4509         return WINED3DERR_INVALIDCALL;
4510     }
4511     
4512     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4513     if (NULL == object ) {
4514         FIXME("(%p)Error allocating memory for stateblock\n", This);
4515         return E_OUTOFMEMORY;
4516     }
4517     TRACE("(%p) created object %p\n", This, object);
4518     object->wineD3DDevice= This;
4519     /** FIXME: object->parent       = parent; **/
4520     object->parent       = NULL;
4521     object->blockType    = WINED3DSBT_RECORDED;
4522     object->ref          = 1;
4523     object->lpVtbl       = &IWineD3DStateBlock_Vtbl;
4524
4525     for(i = 0; i < LIGHTMAP_SIZE; i++) {
4526         list_init(&object->lightMap[i]);
4527     }
4528
4529     temp_result = allocate_shader_constants(object);
4530     if (WINED3D_OK != temp_result)
4531         return temp_result;
4532
4533     IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4534     This->updateStateBlock = object;
4535     This->isRecordingState = TRUE;
4536
4537     TRACE("(%p) recording stateblock %p\n",This , object);
4538     return WINED3D_OK;
4539 }
4540
4541 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4542     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543     unsigned int i, j;
4544     IWineD3DStateBlockImpl *object = This->updateStateBlock;
4545
4546     if (!This->isRecordingState) {
4547         FIXME("(%p) not recording! returning error\n", This);
4548         *ppStateBlock = NULL;
4549         return WINED3DERR_INVALIDCALL;
4550     }
4551
4552     for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4553         if(object->changed.renderState[i]) {
4554             object->contained_render_states[object->num_contained_render_states] = i;
4555             object->num_contained_render_states++;
4556         }
4557     }
4558     for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4559         if(object->changed.transform[i]) {
4560             object->contained_transform_states[object->num_contained_transform_states] = i;
4561             object->num_contained_transform_states++;
4562         }
4563     }
4564     for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4565         if(object->changed.vertexShaderConstantsF[i]) {
4566             object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4567             object->num_contained_vs_consts_f++;
4568         }
4569     }
4570     for(i = 0; i < MAX_CONST_I; i++) {
4571         if(object->changed.vertexShaderConstantsI[i]) {
4572             object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4573             object->num_contained_vs_consts_i++;
4574         }
4575     }
4576     for(i = 0; i < MAX_CONST_B; i++) {
4577         if(object->changed.vertexShaderConstantsB[i]) {
4578             object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4579             object->num_contained_vs_consts_b++;
4580         }
4581     }
4582     for(i = 0; i < MAX_CONST_I; i++) {
4583         if(object->changed.pixelShaderConstantsI[i]) {
4584             object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4585             object->num_contained_ps_consts_i++;
4586         }
4587     }
4588     for(i = 0; i < MAX_CONST_B; i++) {
4589         if(object->changed.pixelShaderConstantsB[i]) {
4590             object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4591             object->num_contained_ps_consts_b++;
4592         }
4593     }
4594     for(i = 0; i < MAX_TEXTURES; i++) {
4595         for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4596             if(object->changed.textureState[i][j]) {
4597                 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4598                 object->contained_tss_states[object->num_contained_tss_states].state = j;
4599                 object->num_contained_tss_states++;
4600             }
4601         }
4602     }
4603     for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4604         for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4605             if(object->changed.samplerState[i][j]) {
4606                 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4607                 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4608                 object->num_contained_sampler_states++;
4609             }
4610         }
4611     }
4612
4613     *ppStateBlock = (IWineD3DStateBlock*) object;
4614     This->isRecordingState = FALSE;
4615     This->updateStateBlock = This->stateBlock;
4616     IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4617     /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4618     TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4619     return WINED3D_OK;
4620 }
4621
4622 /*****
4623  * Scene related functions
4624  *****/
4625 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4626     /* At the moment we have no need for any functionality at the beginning
4627        of a scene                                                          */
4628     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629     TRACE("(%p)\n", This);
4630
4631     if(This->inScene) {
4632         TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4633         return WINED3DERR_INVALIDCALL;
4634     }
4635     This->inScene = TRUE;
4636     return WINED3D_OK;
4637 }
4638
4639 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4640     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641     TRACE("(%p)\n", This);
4642
4643     if(!This->inScene) {
4644         TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4645         return WINED3DERR_INVALIDCALL;
4646     }
4647
4648     if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4649         ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4650     }
4651     /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4652     ENTER_GL();
4653     glFlush();
4654     checkGLcall("glFlush");
4655     LEAVE_GL();
4656
4657     This->inScene = FALSE;
4658     return WINED3D_OK;
4659 }
4660
4661 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4662                                           CONST RECT* pSourceRect, CONST RECT* pDestRect,
4663                                           HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4664     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4665     IWineD3DSwapChain *swapChain = NULL;
4666     int i;
4667     int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4668
4669     TRACE("(%p) Presenting the frame\n", This);
4670
4671     for(i = 0 ; i < swapchains ; i ++) {
4672
4673         IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4674         TRACE("presentinng chain %d, %p\n", i, swapChain);
4675         IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4676         IWineD3DSwapChain_Release(swapChain);
4677     }
4678
4679     return WINED3D_OK;
4680 }
4681
4682 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4683                                         DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4684     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685     IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4686
4687     GLbitfield     glMask = 0;
4688     unsigned int   i;
4689     CONST WINED3DRECT* curRect;
4690
4691     TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4692           Count, pRects, Flags, Color, Z, Stencil);
4693
4694     if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4695         WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4696         /* TODO: What about depth stencil buffers without stencil bits? */
4697         return WINED3DERR_INVALIDCALL;
4698     }
4699
4700     /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4701      * and not the last active one.
4702      */
4703     ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4704     ENTER_GL();
4705
4706     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4707         apply_fbo_state(iface);
4708     }
4709
4710     if (Count > 0 && pRects) {
4711         curRect = pRects;
4712     } else {
4713         curRect = NULL;
4714     }
4715
4716     /* Only set the values up once, as they are not changing */
4717     if (Flags & WINED3DCLEAR_STENCIL) {
4718         glClearStencil(Stencil);
4719         checkGLcall("glClearStencil");
4720         glMask = glMask | GL_STENCIL_BUFFER_BIT;
4721         glStencilMask(0xFFFFFFFF);
4722     }
4723
4724     if (Flags & WINED3DCLEAR_ZBUFFER) {
4725         glDepthMask(GL_TRUE);
4726         glClearDepth(Z);
4727         checkGLcall("glClearDepth");
4728         glMask = glMask | GL_DEPTH_BUFFER_BIT;
4729         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4730     }
4731
4732     if (Flags & WINED3DCLEAR_TARGET) {
4733         TRACE("Clearing screen with glClear to color %x\n", Color);
4734         glClearColor(D3DCOLOR_R(Color),
4735                      D3DCOLOR_G(Color),
4736                      D3DCOLOR_B(Color),
4737                      D3DCOLOR_A(Color));
4738         checkGLcall("glClearColor");
4739
4740         /* Clear ALL colors! */
4741         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4742         glMask = glMask | GL_COLOR_BUFFER_BIT;
4743     }
4744
4745     if (!curRect) {
4746         /* In drawable flag is set below */
4747
4748         if (This->render_offscreen) {
4749             glScissor(This->stateBlock->viewport.X,
4750                        This->stateBlock->viewport.Y,
4751                        This->stateBlock->viewport.Width,
4752                        This->stateBlock->viewport.Height);
4753         } else {
4754             glScissor(This->stateBlock->viewport.X,
4755                       (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4756                       (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4757                        This->stateBlock->viewport.Width,
4758                        This->stateBlock->viewport.Height);
4759         }
4760         checkGLcall("glScissor");
4761         glClear(glMask);
4762         checkGLcall("glClear");
4763     } else {
4764         if(!(target->Flags & SFLAG_INDRAWABLE) &&
4765            !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4766
4767             if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4768                curRect[0].x2 < target->currentDesc.Width ||
4769                curRect[0].y2 < target->currentDesc.Height) {
4770                 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4771                 blt_to_drawable(This, target);
4772             }
4773         }
4774
4775         /* Now process each rect in turn */
4776         for (i = 0; i < Count; i++) {
4777             /* Note gl uses lower left, width/height */
4778             TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4779                   curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4780                   curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4781                   curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4782
4783             /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4784              * The rectangle is not cleared, no error is returned, but further rectanlges are
4785              * still cleared if they are valid
4786              */
4787             if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4788                 TRACE("Rectangle with negative dimensions, ignoring\n");
4789                 continue;
4790             }
4791
4792             if(This->render_offscreen) {
4793                 glScissor(curRect[i].x1, curRect[i].y1,
4794                           curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4795             } else {
4796                 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4797                           curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4798             }
4799             checkGLcall("glScissor");
4800
4801             glClear(glMask);
4802             checkGLcall("glClear");
4803         }
4804     }
4805
4806     /* Restore the old values (why..?) */
4807     if (Flags & WINED3DCLEAR_STENCIL) {
4808         glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4809     }
4810     if (Flags & WINED3DCLEAR_TARGET) {
4811         DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4812         glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4813                     mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4814                     mask & WINED3DCOLORWRITEENABLE_BLUE  ? GL_TRUE : GL_FALSE,
4815                     mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4816     }
4817
4818     LEAVE_GL();
4819
4820     /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4821      * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4822      */
4823     if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4824         target->Flags |= SFLAG_INTEXTURE;
4825         target->Flags &= ~SFLAG_INSYSMEM;
4826     } else {
4827         target->Flags |= SFLAG_INDRAWABLE;
4828         target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4829     }
4830     return WINED3D_OK;
4831 }
4832
4833 /*****
4834  * Drawing functions
4835  *****/
4836 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4837                                                 UINT PrimitiveCount) {
4838
4839     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840
4841     TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4842                                debug_d3dprimitivetype(PrimitiveType),
4843                                StartVertex, PrimitiveCount);
4844
4845     /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4846     if(This->stateBlock->streamIsUP) {
4847         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4848         This->stateBlock->streamIsUP = FALSE;
4849     }
4850
4851     if(This->stateBlock->loadBaseVertexIndex != 0) {
4852         This->stateBlock->loadBaseVertexIndex = 0;
4853         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4854     }
4855     /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4856     drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4857                   0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4858     return WINED3D_OK;
4859 }
4860
4861 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4862 static HRESULT  WINAPI  IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4863                                                            WINED3DPRIMITIVETYPE PrimitiveType,
4864                                                            UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4865
4866     IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;
4867     UINT                 idxStride = 2;
4868     IWineD3DIndexBuffer *pIB;
4869     WINED3DINDEXBUFFER_DESC  IdxBufDsc;
4870     GLuint vbo;
4871
4872     pIB = This->stateBlock->pIndexData;
4873     if (!pIB) {
4874         /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4875          * without an index buffer set. (The first time at least...)
4876          * D3D8 simply dies, but I doubt it can do much harm to return
4877          * D3DERR_INVALIDCALL there as well. */
4878         ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4879         return WINED3DERR_INVALIDCALL;
4880     }
4881
4882     if(This->stateBlock->streamIsUP) {
4883         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4884         This->stateBlock->streamIsUP = FALSE;
4885     }
4886     vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4887
4888     TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4889           PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4890           minIndex, NumVertices, startIndex, primCount);
4891
4892     IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4893     if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4894         idxStride = 2;
4895     } else {
4896         idxStride = 4;
4897     }
4898
4899     if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4900         This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4901         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4902     }
4903
4904     drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4905                    idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4906
4907     return WINED3D_OK;
4908 }
4909
4910 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4911                                                     UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4912                                                     UINT VertexStreamZeroStride) {
4913     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914     IWineD3DVertexBuffer *vb;
4915
4916     TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4917              debug_d3dprimitivetype(PrimitiveType),
4918              PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4919
4920     /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4921     vb = This->stateBlock->streamSource[0];
4922     This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4923     if(vb) IWineD3DVertexBuffer_Release(vb);
4924     This->stateBlock->streamOffset[0] = 0;
4925     This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4926     This->stateBlock->streamIsUP = TRUE;
4927     This->stateBlock->loadBaseVertexIndex = 0;
4928
4929     /* TODO: Only mark dirty if drawing from a different UP address */
4930     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4931
4932     drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0  /* NumVertices */,
4933                   0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4934
4935     /* MSDN specifies stream zero settings must be set to NULL */
4936     This->stateBlock->streamStride[0] = 0;
4937     This->stateBlock->streamSource[0] = NULL;
4938
4939     /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4940      * the new stream sources or use UP drawing again
4941      */
4942     return WINED3D_OK;
4943 }
4944
4945 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4946                                                              UINT MinVertexIndex, UINT NumVertices,
4947                                                              UINT PrimitiveCount, CONST void* pIndexData,
4948                                                              WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4949                                                              UINT VertexStreamZeroStride) {
4950     int                 idxStride;
4951     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4952     IWineD3DVertexBuffer *vb;
4953     IWineD3DIndexBuffer *ib;
4954
4955     TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4956              This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4957              MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4958              IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4959
4960     if (IndexDataFormat == WINED3DFMT_INDEX16) {
4961         idxStride = 2;
4962     } else {
4963         idxStride = 4;
4964     }
4965
4966     /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4967     vb = This->stateBlock->streamSource[0];
4968     This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4969     if(vb) IWineD3DVertexBuffer_Release(vb);
4970     This->stateBlock->streamIsUP = TRUE;
4971     This->stateBlock->streamOffset[0] = 0;
4972     This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4973
4974     /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4975     This->stateBlock->baseVertexIndex = 0;
4976     This->stateBlock->loadBaseVertexIndex = 0;
4977     /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4978     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4979     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4980
4981     drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4982
4983     /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4984     This->stateBlock->streamSource[0] = NULL;
4985     This->stateBlock->streamStride[0] = 0;
4986     ib = This->stateBlock->pIndexData;
4987     if(ib) {
4988         IWineD3DIndexBuffer_Release(ib);
4989         This->stateBlock->pIndexData = NULL;
4990     }
4991     /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4992      * SetStreamSource to specify a vertex buffer
4993      */
4994
4995     return WINED3D_OK;
4996 }
4997
4998 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4999     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5000
5001     /* Mark the state dirty until we have nicer tracking
5002      * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5003      * that value.
5004      */
5005     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5006     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5007     This->stateBlock->baseVertexIndex = 0;
5008     This->up_strided = DrawPrimStrideData;
5009     drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5010     This->up_strided = NULL;
5011     return WINED3D_OK;
5012 }
5013
5014 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5015     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5016     DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5017
5018     /* Mark the state dirty until we have nicer tracking
5019      * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5020      * that value.
5021      */
5022     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5023     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5024     This->stateBlock->streamIsUP = TRUE;
5025     This->stateBlock->baseVertexIndex = 0;
5026     This->up_strided = DrawPrimStrideData;
5027     drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5028     This->up_strided = NULL;
5029     return WINED3D_OK;
5030 }
5031
5032 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5033     /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5034      * not callable by the app directly no parameter validation checks are needed here.
5035      */
5036     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5037     WINED3DLOCKED_BOX src;
5038     WINED3DLOCKED_BOX dst;
5039     HRESULT hr;
5040     TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5041
5042     /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5043      * dirtification to improve loading performance.
5044      */
5045     hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5046     if(FAILED(hr)) return hr;
5047     hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5048     if(FAILED(hr)) {
5049     IWineD3DVolume_UnlockBox(pSourceVolume);
5050             return hr;
5051     }
5052
5053     memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5054
5055     hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5056     if(FAILED(hr)) {
5057         IWineD3DVolume_UnlockBox(pSourceVolume);
5058     } else {
5059         hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5060     }
5061     return hr;
5062 }
5063
5064 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5065 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture,  IWineD3DBaseTexture *pDestinationTexture){
5066     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067     HRESULT hr = WINED3D_OK;
5068     WINED3DRESOURCETYPE sourceType;
5069     WINED3DRESOURCETYPE destinationType;
5070     int i ,levels;
5071
5072     /* TODO: think about moving the code into IWineD3DBaseTexture  */
5073
5074     TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5075
5076     /* verify that the source and destination textures aren't NULL */
5077     if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5078         WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5079              This, pSourceTexture, pDestinationTexture);
5080         hr = WINED3DERR_INVALIDCALL;
5081     }
5082
5083     if (pSourceTexture == pDestinationTexture) {
5084         WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5085              This, pSourceTexture, pDestinationTexture);
5086         hr = WINED3DERR_INVALIDCALL;
5087     }
5088     /* Verify that the source and destination textures are the same type */
5089     sourceType      = IWineD3DBaseTexture_GetType(pSourceTexture);
5090     destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5091
5092     if (sourceType != destinationType) {
5093         WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5094              This);
5095         hr = WINED3DERR_INVALIDCALL;
5096     }
5097
5098     /* check that both textures have the identical numbers of levels  */
5099     if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture)  != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5100         WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5101         hr = WINED3DERR_INVALIDCALL;
5102     }
5103
5104     if (WINED3D_OK == hr) {
5105
5106         /* Make sure that the destination texture is loaded */
5107         IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5108
5109         /* Update every surface level of the texture */
5110         levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5111
5112         switch (sourceType) {
5113         case WINED3DRTYPE_TEXTURE:
5114             {
5115                 IWineD3DSurface *srcSurface;
5116                 IWineD3DSurface *destSurface;
5117
5118                 for (i = 0 ; i < levels ; ++i) {
5119                     IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture,      i, &srcSurface);
5120                     IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5121                     hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5122                     IWineD3DSurface_Release(srcSurface);
5123                     IWineD3DSurface_Release(destSurface);
5124                     if (WINED3D_OK != hr) {
5125                         WARN("(%p) : Call to update surface failed\n", This);
5126                         return hr;
5127                     }
5128                 }
5129             }
5130             break;
5131         case WINED3DRTYPE_CUBETEXTURE:
5132             {
5133                 IWineD3DSurface *srcSurface;
5134                 IWineD3DSurface *destSurface;
5135                 WINED3DCUBEMAP_FACES faceType;
5136
5137                 for (i = 0 ; i < levels ; ++i) {
5138                     /* Update each cube face */
5139                     for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5140                         hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture,      faceType, i, &srcSurface);
5141                         if (WINED3D_OK != hr) {
5142                             FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5143                         } else {
5144                             TRACE("Got srcSurface %p\n", srcSurface);
5145                         }
5146                         hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5147                         if (WINED3D_OK != hr) {
5148                             FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5149                         } else {
5150                             TRACE("Got desrSurface %p\n", destSurface);
5151                         }
5152                         hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5153                         IWineD3DSurface_Release(srcSurface);
5154                         IWineD3DSurface_Release(destSurface);
5155                         if (WINED3D_OK != hr) {
5156                             WARN("(%p) : Call to update surface failed\n", This);
5157                             return hr;
5158                         }
5159                     }
5160                 }
5161             }
5162             break;
5163
5164         case WINED3DRTYPE_VOLUMETEXTURE:
5165             {
5166                 IWineD3DVolume  *srcVolume  = NULL;
5167                 IWineD3DVolume  *destVolume = NULL;
5168
5169                 for (i = 0 ; i < levels ; ++i) {
5170                     IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture,      i, &srcVolume);
5171                     IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5172                     hr =  IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5173                     IWineD3DVolume_Release(srcVolume);
5174                     IWineD3DVolume_Release(destVolume);
5175                     if (WINED3D_OK != hr) {
5176                         WARN("(%p) : Call to update volume failed\n", This);
5177                         return hr;
5178                     }
5179                 }
5180             }
5181             break;
5182
5183         default:
5184             FIXME("(%p) : Unsupported source and destination type\n", This);
5185             hr = WINED3DERR_INVALIDCALL;
5186         }
5187     }
5188
5189     return hr;
5190 }
5191
5192 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5193     IWineD3DSwapChain *swapChain;
5194     HRESULT hr;
5195     hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, (IWineD3DSwapChain **)&swapChain);
5196     if(hr == WINED3D_OK) {
5197         hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5198                 IWineD3DSwapChain_Release(swapChain);
5199     }
5200     return hr;
5201 }
5202
5203 static HRESULT  WINAPI  IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5204     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205     /* return a sensible default */
5206     *pNumPasses = 1;
5207     /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5208     FIXME("(%p) : stub\n", This);
5209     return WINED3D_OK;
5210 }
5211
5212 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5213     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5214     int j;
5215     TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5216     if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5217         WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5218         return WINED3DERR_INVALIDCALL;
5219     }
5220     for (j = 0; j < 256; ++j) {
5221         This->palettes[PaletteNumber][j].peRed   = pEntries[j].peRed;
5222         This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5223         This->palettes[PaletteNumber][j].peBlue  = pEntries[j].peBlue;
5224         This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5225     }
5226     TRACE("(%p) : returning\n", This);
5227     return WINED3D_OK;
5228 }
5229
5230 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5231     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232     int j;
5233     TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5234     if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5235         WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5236         return WINED3DERR_INVALIDCALL;
5237     }
5238     for (j = 0; j < 256; ++j) {
5239         pEntries[j].peRed   = This->palettes[PaletteNumber][j].peRed;
5240         pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5241         pEntries[j].peBlue  = This->palettes[PaletteNumber][j].peBlue;
5242         pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5243     }
5244     TRACE("(%p) : returning\n", This);
5245     return WINED3D_OK;
5246 }
5247
5248 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5249     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250     TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5251     if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5252         WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5253         return WINED3DERR_INVALIDCALL;
5254     }
5255     /*TODO: stateblocks */
5256     This->currentPalette = PaletteNumber;
5257     TRACE("(%p) : returning\n", This);
5258     return WINED3D_OK;
5259 }
5260
5261 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5262     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5263     if (PaletteNumber == NULL) {
5264         WARN("(%p) : returning Invalid Call\n", This);
5265         return WINED3DERR_INVALIDCALL;
5266     }
5267     /*TODO: stateblocks */
5268     *PaletteNumber = This->currentPalette;
5269     TRACE("(%p) : returning  %u\n", This, *PaletteNumber);
5270     return WINED3D_OK;
5271 }
5272
5273 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5274     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5275     static BOOL showFixmes = TRUE;
5276     if (showFixmes) {
5277         FIXME("(%p) : stub\n", This);
5278         showFixmes = FALSE;
5279     }
5280
5281     This->softwareVertexProcessing = bSoftware;
5282     return WINED3D_OK;
5283 }
5284
5285
5286 static BOOL     WINAPI  IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5287     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5288     static BOOL showFixmes = TRUE;
5289     if (showFixmes) {
5290         FIXME("(%p) : stub\n", This);
5291         showFixmes = FALSE;
5292     }
5293     return This->softwareVertexProcessing;
5294 }
5295
5296
5297 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5298     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5299     IWineD3DSwapChain *swapChain;
5300     HRESULT hr;
5301
5302     TRACE("(%p) :  SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5303
5304     hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, (IWineD3DSwapChain **)&swapChain);
5305     if(hr == WINED3D_OK){
5306         hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5307         IWineD3DSwapChain_Release(swapChain);
5308     }else{
5309         FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5310     }
5311     return hr;
5312 }
5313
5314
5315 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5316     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317     static BOOL showfixmes = TRUE;
5318     if(nSegments != 0.0f) {
5319         if( showfixmes) {
5320             FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5321             showfixmes = FALSE;
5322         }
5323     }
5324     return WINED3D_OK;
5325 }
5326
5327 static float    WINAPI  IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5328     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329     static BOOL showfixmes = TRUE;
5330     if( showfixmes) {
5331         FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5332         showfixmes = FALSE;
5333     }
5334     return 0.0f;
5335 }
5336
5337 static HRESULT  WINAPI  IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5338     IWineD3DDeviceImpl  *This         = (IWineD3DDeviceImpl *) iface;
5339     /** TODO: remove casts to IWineD3DSurfaceImpl
5340      *       NOTE: move code to surface to accomplish this
5341       ****************************************/
5342     IWineD3DSurfaceImpl *pSrcSurface  = (IWineD3DSurfaceImpl *)pSourceSurface;
5343     int srcWidth, srcHeight;
5344     unsigned int  srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5345     WINED3DFORMAT destFormat, srcFormat;
5346     UINT          destSize;
5347     int srcLeft, destLeft, destTop;
5348     WINED3DPOOL       srcPool, destPool;
5349     int offset    = 0;
5350     int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5351     glDescriptor *glDescription = NULL;
5352     GLenum dummy;
5353     int bpp;
5354     CONVERT_TYPES convert = NO_CONVERSION;
5355
5356     WINED3DSURFACE_DESC  winedesc;
5357
5358     TRACE("(%p) : Source (%p)  Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5359     memset(&winedesc, 0, sizeof(winedesc));
5360     winedesc.Width  = &srcSurfaceWidth;
5361     winedesc.Height = &srcSurfaceHeight;
5362     winedesc.Pool   = &srcPool;
5363     winedesc.Format = &srcFormat;
5364
5365     IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5366
5367     winedesc.Width  = &destSurfaceWidth;
5368     winedesc.Height = &destSurfaceHeight;
5369     winedesc.Pool   = &destPool;
5370     winedesc.Format = &destFormat;
5371     winedesc.Size   = &destSize;
5372
5373     IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5374
5375     if(srcPool != WINED3DPOOL_SYSTEMMEM  || destPool != WINED3DPOOL_DEFAULT){
5376         WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5377         return WINED3DERR_INVALIDCALL;
5378     }
5379
5380     /* This call loads the opengl surface directly, instead of copying the surface to the
5381      * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5382      * copy in sysmem and use regular surface loading.
5383      */
5384     d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5385                     &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5386     if(convert != NO_CONVERSION) {
5387         return IWineD3DSurface_BltFast(pDestinationSurface,
5388                                         pDestPoint  ? pDestPoint->x : 0,
5389                                         pDestPoint  ? pDestPoint->y : 0,
5390                                         pSourceSurface, (RECT *) pSourceRect, 0);
5391     }
5392
5393     if (destFormat == WINED3DFMT_UNKNOWN) {
5394         TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5395         IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5396
5397         /* Get the update surface description */
5398         IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5399     }
5400
5401     ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5402
5403     ENTER_GL();
5404
5405     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5406         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5407         checkGLcall("glActiveTextureARB");
5408     }
5409
5410     /* Make sure the surface is loaded and up to date */
5411     IWineD3DSurface_PreLoad(pDestinationSurface);
5412
5413     IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5414
5415     /* this needs to be done in lines if the sourceRect != the sourceWidth */
5416     srcWidth   = pSourceRect ? pSourceRect->right - pSourceRect->left   : srcSurfaceWidth;
5417     srcHeight  = pSourceRect ? pSourceRect->bottom - pSourceRect->top   : srcSurfaceHeight;
5418     srcLeft    = pSourceRect ? pSourceRect->left : 0;
5419     destLeft   = pDestPoint  ? pDestPoint->x : 0;
5420     destTop    = pDestPoint  ? pDestPoint->y : 0;
5421
5422
5423     /* This function doesn't support compressed textures
5424     the pitch is just bytesPerPixel * width */
5425     if(srcWidth != srcSurfaceWidth  || srcLeft ){
5426         rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5427         offset   += srcLeft * pSrcSurface->bytesPerPixel;
5428         /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5429     }
5430     /* TODO DXT formats */
5431
5432     if(pSourceRect != NULL && pSourceRect->top != 0){
5433        offset +=  pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5434     }
5435     TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5436     ,This
5437     ,glDescription->level
5438     ,destLeft
5439     ,destTop
5440     ,srcWidth
5441     ,srcHeight
5442     ,glDescription->glFormat
5443     ,glDescription->glType
5444     ,IWineD3DSurface_GetData(pSourceSurface)
5445     );
5446
5447     /* Sanity check */
5448     if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5449
5450         /* need to lock the surface to get the data */
5451         FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5452     }
5453
5454     /* TODO: Cube and volume support */
5455     if(rowoffset != 0){
5456         /* not a whole row so we have to do it a line at a time */
5457         int j;
5458
5459         /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5460         const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5461
5462         for(j = destTop ; j < (srcHeight + destTop) ; j++){
5463
5464                 glTexSubImage2D(glDescription->target
5465                     ,glDescription->level
5466                     ,destLeft
5467                     ,j
5468                     ,srcWidth
5469                     ,1
5470                     ,glDescription->glFormat
5471                     ,glDescription->glType
5472                     ,data /* could be quicker using */
5473                 );
5474             data += rowoffset;
5475         }
5476
5477     } else { /* Full width, so just write out the whole texture */
5478
5479         if (WINED3DFMT_DXT1 == destFormat ||
5480             WINED3DFMT_DXT2 == destFormat ||
5481             WINED3DFMT_DXT3 == destFormat ||
5482             WINED3DFMT_DXT4 == destFormat ||
5483             WINED3DFMT_DXT5 == destFormat) {
5484             if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5485                 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5486                     /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5487                     FIXME("Updating part of a compressed texture is not supported at the moment\n");
5488                 } if (destFormat != srcFormat) {
5489                     FIXME("Updating mixed format compressed texture is not curretly support\n");
5490                 } else {
5491                     GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5492                                                         glDescription->level,
5493                                                         glDescription->glFormatInternal,
5494                                                         srcWidth,
5495                                                         srcHeight,
5496                                                         0,
5497                                                         destSize,
5498                                                         IWineD3DSurface_GetData(pSourceSurface));
5499                 }
5500             } else {
5501                 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5502             }
5503
5504
5505         } else {
5506             glTexSubImage2D(glDescription->target
5507                     ,glDescription->level
5508                     ,destLeft
5509                     ,destTop
5510                     ,srcWidth
5511                     ,srcHeight
5512                     ,glDescription->glFormat
5513                     ,glDescription->glType
5514                     ,IWineD3DSurface_GetData(pSourceSurface)
5515                 );
5516         }
5517      }
5518     checkGLcall("glTexSubImage2D");
5519
5520     LEAVE_GL();
5521
5522     ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5523     ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5524     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5525
5526     return WINED3D_OK;
5527 }
5528
5529 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5530     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5531     struct WineD3DRectPatch *patch;
5532     unsigned int i;
5533     struct list *e;
5534     BOOL found;
5535     TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5536
5537     if(!(Handle || pRectPatchInfo)) {
5538         /* TODO: Write a test for the return value, thus the FIXME */
5539         FIXME("Both Handle and pRectPatchInfo are NULL\n");
5540         return WINED3DERR_INVALIDCALL;
5541     }
5542
5543     if(Handle) {
5544         i = PATCHMAP_HASHFUNC(Handle);
5545         found = FALSE;
5546         LIST_FOR_EACH(e, &This->patches[i]) {
5547             patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5548             if(patch->Handle == Handle) {
5549                 found = TRUE;
5550                 break;
5551             }
5552         }
5553
5554         if(!found) {
5555             TRACE("Patch does not exist. Creating a new one\n");
5556             patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5557             patch->Handle = Handle;
5558             list_add_head(&This->patches[i], &patch->entry);
5559         } else {
5560             TRACE("Found existing patch %p\n", patch);
5561         }
5562     } else {
5563         /* Since opengl does not load tesselated vertex attributes into numbered vertex
5564          * attributes we have to tesselate, read back, and draw. This needs a patch
5565          * management structure instance. Create one.
5566          *
5567          * A possible improvement is to check if a vertex shader is used, and if not directly
5568          * draw the patch.
5569          */
5570         FIXME("Drawing an uncached patch. This is slow\n");
5571         patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5572     }
5573
5574     if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5575        pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5576        (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5577         HRESULT hr;
5578         TRACE("Tesselation density or patch info changed, retesselating\n");
5579
5580         if(pRectPatchInfo) {
5581             memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5582         }
5583         patch->numSegs[0] = pNumSegs[0];
5584         patch->numSegs[1] = pNumSegs[1];
5585         patch->numSegs[2] = pNumSegs[2];
5586         patch->numSegs[3] = pNumSegs[3];
5587
5588         hr = tesselate_rectpatch(This, patch);
5589         if(FAILED(hr)) {
5590             WARN("Patch tesselation failed\n");
5591
5592             /* Do not release the handle to store the params of the patch */
5593             if(!Handle) {
5594                 HeapFree(GetProcessHeap(), 0, patch);
5595             }
5596             return hr;
5597         }
5598     }
5599
5600     This->currentPatch = patch;
5601     IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5602     This->currentPatch = NULL;
5603
5604     /* Destroy uncached patches */
5605     if(!Handle) {
5606         HeapFree(GetProcessHeap(), 0, patch->mem);
5607         HeapFree(GetProcessHeap(), 0, patch);
5608     }
5609     return WINED3D_OK;
5610 }
5611
5612 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5613 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5614     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5615     TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5616     FIXME("(%p) : Stub\n", This);
5617     return WINED3D_OK;
5618 }
5619
5620 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5621     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5622     int i;
5623     struct WineD3DRectPatch *patch;
5624     struct list *e;
5625     TRACE("(%p) Handle(%d)\n", This, Handle);
5626
5627     i = PATCHMAP_HASHFUNC(Handle);
5628     LIST_FOR_EACH(e, &This->patches[i]) {
5629         patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5630         if(patch->Handle == Handle) {
5631             TRACE("Deleting patch %p\n", patch);
5632             list_remove(&patch->entry);
5633             HeapFree(GetProcessHeap(), 0, patch->mem);
5634             HeapFree(GetProcessHeap(), 0, patch);
5635             return WINED3D_OK;
5636         }
5637     }
5638
5639     /* TODO: Write a test for the return value */
5640     FIXME("Attempt to destroy nonexistant patch\n");
5641     return WINED3DERR_INVALIDCALL;
5642 }
5643
5644 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5645     HRESULT hr;
5646     IWineD3DSwapChain *swapchain;
5647
5648     hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5649     if (SUCCEEDED(hr)) {
5650         IWineD3DSwapChain_Release((IUnknown *)swapchain);
5651         return swapchain;
5652     }
5653
5654     return NULL;
5655 }
5656
5657 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5658     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659
5660     if (!*fbo) {
5661         GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5662         checkGLcall("glGenFramebuffersEXT()");
5663     }
5664     GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5665     checkGLcall("glBindFramebuffer()");
5666 }
5667
5668 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5669     const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5670     IWineD3DBaseTextureImpl *texture_impl;
5671     GLenum texttarget, target;
5672     GLint old_binding;
5673
5674     texttarget = surface_impl->glDescription.target;
5675     target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5676     glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5677
5678     IWineD3DSurface_PreLoad(surface);
5679
5680     glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5681     glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5682     glBindTexture(target, old_binding);
5683
5684     /* Update base texture states array */
5685     if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5686         texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5687         texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5688         if (texture_impl->baseTexture.bindCount) {
5689             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5690         }
5691
5692         IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5693     }
5694
5695     GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5696             surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5697
5698     checkGLcall("attach_surface_fbo");
5699 }
5700
5701 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5702     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5703     IWineD3DSwapChain *swapchain;
5704
5705     swapchain = get_swapchain(surface);
5706     if (swapchain) {
5707         GLenum buffer;
5708
5709         TRACE("Surface %p is onscreen\n", surface);
5710
5711         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5712         buffer = surface_get_gl_buffer(surface, swapchain);
5713         glDrawBuffer(buffer);
5714         checkGLcall("glDrawBuffer()");
5715     } else {
5716         TRACE("Surface %p is offscreen\n", surface);
5717         bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5718         attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5719     }
5720
5721     if (rect) {
5722         glEnable(GL_SCISSOR_TEST);
5723         if(!swapchain) {
5724             glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5725         } else {
5726             glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5727                     rect->x2 - rect->x1, rect->y2 - rect->y1);
5728         }
5729         checkGLcall("glScissor");
5730     } else {
5731         glDisable(GL_SCISSOR_TEST);
5732     }
5733     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5734
5735     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5736     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5737
5738     glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5739     glClear(GL_COLOR_BUFFER_BIT);
5740     checkGLcall("glClear");
5741
5742     if (This->render_offscreen) {
5743         bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5744     } else {
5745         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5746         checkGLcall("glBindFramebuffer()");
5747     }
5748
5749     if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5750             && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5751         glDrawBuffer(GL_BACK);
5752         checkGLcall("glDrawBuffer()");
5753     }
5754 }
5755
5756 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5757     unsigned int r, g, b, a;
5758     DWORD ret;
5759
5760     if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5761        destfmt == WINED3DFMT_R8G8B8)
5762         return color;
5763
5764     TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5765
5766     a = (color & 0xff000000) >> 24;
5767     r = (color & 0x00ff0000) >> 16;
5768     g = (color & 0x0000ff00) >>  8;
5769     b = (color & 0x000000ff) >>  0;
5770
5771     switch(destfmt)
5772     {
5773         case WINED3DFMT_R5G6B5:
5774             if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5775             r = (r * 32) / 256;
5776             g = (g * 64) / 256;
5777             b = (b * 32) / 256;
5778             ret  = r << 11;
5779             ret |= g << 5;
5780             ret |= b;
5781             TRACE("Returning %08x\n", ret);
5782             return ret;
5783
5784         case WINED3DFMT_X1R5G5B5:
5785         case WINED3DFMT_A1R5G5B5:
5786             a = (a *  2) / 256;
5787             r = (r * 32) / 256;
5788             g = (g * 32) / 256;
5789             b = (b * 32) / 256;
5790             ret  = a << 15;
5791             ret |= r << 10;
5792             ret |= g <<  5;
5793             ret |= b <<  0;
5794             TRACE("Returning %08x\n", ret);
5795             return ret;
5796
5797         case WINED3DFMT_A8:
5798             TRACE("Returning %08x\n", a);
5799             return a;
5800
5801         case WINED3DFMT_X4R4G4B4:
5802         case WINED3DFMT_A4R4G4B4:
5803             a = (a * 16) / 256;
5804             r = (r * 16) / 256;
5805             g = (g * 16) / 256;
5806             b = (b * 16) / 256;
5807             ret  = a << 12;
5808             ret |= r <<  8;
5809             ret |= g <<  4;
5810             ret |= b <<  0;
5811             TRACE("Returning %08x\n", ret);
5812             return ret;
5813
5814         case WINED3DFMT_R3G3B2:
5815             r = (r * 8) / 256;
5816             g = (g * 8) / 256;
5817             b = (b * 4) / 256;
5818             ret  = r <<  5;
5819             ret |= g <<  2;
5820             ret |= b <<  0;
5821             TRACE("Returning %08x\n", ret);
5822             return ret;
5823
5824         case WINED3DFMT_X8B8G8R8:
5825         case WINED3DFMT_A8B8G8R8:
5826             ret  = a << 24;
5827             ret |= b << 16;
5828             ret |= g <<  8;
5829             ret |= r <<  0;
5830             TRACE("Returning %08x\n", ret);
5831             return ret;
5832
5833         case WINED3DFMT_A2R10G10B10:
5834             a = (a *    4) / 256;
5835             r = (r * 1024) / 256;
5836             g = (g * 1024) / 256;
5837             b = (b * 1024) / 256;
5838             ret  = a << 30;
5839             ret |= r << 20;
5840             ret |= g << 10;
5841             ret |= b <<  0;
5842             TRACE("Returning %08x\n", ret);
5843             return ret;
5844
5845         case WINED3DFMT_A2B10G10R10:
5846             a = (a *    4) / 256;
5847             r = (r * 1024) / 256;
5848             g = (g * 1024) / 256;
5849             b = (b * 1024) / 256;
5850             ret  = a << 30;
5851             ret |= b << 20;
5852             ret |= g << 10;
5853             ret |= r <<  0;
5854             TRACE("Returning %08x\n", ret);
5855             return ret;
5856
5857         default:
5858             FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5859             return 0;
5860     }
5861 }
5862
5863 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5864     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5865     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5866     WINEDDBLTFX BltFx;
5867     TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5868
5869     if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5870         FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5871         return WINED3DERR_INVALIDCALL;
5872     }
5873
5874     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5875         color_fill_fbo(iface, pSurface, pRect, color);
5876         return WINED3D_OK;
5877     } else {
5878         /* Just forward this to the DirectDraw blitting engine */
5879         memset(&BltFx, 0, sizeof(BltFx));
5880         BltFx.dwSize = sizeof(BltFx);
5881         BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5882         return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5883     }
5884 }
5885
5886 /* rendertarget and deptth stencil functions */
5887 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5888     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5889
5890     if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5891         ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5892         return WINED3DERR_INVALIDCALL;
5893     }
5894
5895     *ppRenderTarget = This->render_targets[RenderTargetIndex];
5896     TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5897     /* Note inc ref on returned surface */
5898     if(*ppRenderTarget != NULL)
5899         IWineD3DSurface_AddRef(*ppRenderTarget);
5900     return WINED3D_OK;
5901 }
5902
5903 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5904     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5905     IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5906     IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5907     IWineD3DSwapChainImpl *Swapchain;
5908     HRESULT hr;
5909
5910     TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5911
5912     hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5913     if(hr != WINED3D_OK) {
5914         ERR("Can't get the swapchain\n");
5915         return hr;
5916     }
5917
5918     /* Make sure to release the swapchain */
5919     IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5920
5921     if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5922         ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5923         return WINED3DERR_INVALIDCALL;
5924     }
5925     else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5926         ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5927         return WINED3DERR_INVALIDCALL;
5928     }
5929
5930     if(Swapchain->frontBuffer != Front) {
5931         TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5932
5933         if(Swapchain->frontBuffer)
5934             IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5935         Swapchain->frontBuffer = Front;
5936
5937         if(Swapchain->frontBuffer) {
5938             IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5939         }
5940     }
5941
5942     if(Back && !Swapchain->backBuffer) {
5943         /* We need memory for the back buffer array - only one back buffer this way */
5944         Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5945         if(!Swapchain->backBuffer) {
5946             ERR("Out of memory\n");
5947             return E_OUTOFMEMORY;
5948         }
5949     }
5950
5951     if(Swapchain->backBuffer[0] != Back) {
5952         TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5953
5954         /* What to do about the context here in the case of multithreading? Not sure.
5955          * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5956          */
5957         ENTER_GL();
5958         if(!Swapchain->backBuffer[0]) {
5959             /* GL was told to draw to the front buffer at creation,
5960              * undo that
5961              */
5962             glDrawBuffer(GL_BACK);
5963             checkGLcall("glDrawBuffer(GL_BACK)");
5964             /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5965             Swapchain->presentParms.BackBufferCount = 1;
5966         } else if (!Back) {
5967             /* That makes problems - disable for now */
5968             /* glDrawBuffer(GL_FRONT); */
5969             checkGLcall("glDrawBuffer(GL_FRONT)");
5970             /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5971             Swapchain->presentParms.BackBufferCount = 0;
5972         }
5973         LEAVE_GL();
5974
5975         if(Swapchain->backBuffer[0])
5976             IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5977         Swapchain->backBuffer[0] = Back;
5978
5979         if(Swapchain->backBuffer[0]) {
5980             IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5981         } else {
5982             HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5983         }
5984
5985     }
5986
5987     return WINED3D_OK;
5988 }
5989
5990 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5991     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5992     *ppZStencilSurface = This->depthStencilBuffer;
5993     TRACE("(%p) : zStencilSurface  returning %p\n", This,  *ppZStencilSurface);
5994
5995     if(*ppZStencilSurface != NULL) {
5996         /* Note inc ref on returned surface */
5997         IWineD3DSurface_AddRef(*ppZStencilSurface);
5998         return WINED3D_OK;
5999     } else {
6000         return WINED3DERR_NOTFOUND;
6001     }
6002 }
6003
6004 /* TODO: Handle stencil attachments */
6005 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6006     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6007     IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6008
6009     TRACE("Set depth stencil to %p\n", depth_stencil);
6010
6011     if (depth_stencil_impl) {
6012         if (depth_stencil_impl->current_renderbuffer) {
6013             GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6014             checkGLcall("glFramebufferRenderbufferEXT()");
6015         } else {
6016             IWineD3DBaseTextureImpl *texture_impl;
6017             GLenum texttarget, target;
6018             GLint old_binding = 0;
6019
6020             texttarget = depth_stencil_impl->glDescription.target;
6021             target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6022             glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6023
6024             IWineD3DSurface_PreLoad(depth_stencil);
6025
6026             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6027             glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6028             glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6029             glBindTexture(target, old_binding);
6030
6031             /* Update base texture states array */
6032             if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6033                 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6034                 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6035                 if (texture_impl->baseTexture.bindCount) {
6036                     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6037                 }
6038
6039                 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6040             }
6041
6042             GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6043                     depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6044             checkGLcall("glFramebufferTexture2DEXT()");
6045         }
6046     } else {
6047         GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6048         checkGLcall("glFramebufferTexture2DEXT()");
6049     }
6050 }
6051
6052 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6053     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6054     IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6055
6056     TRACE("Set render target %u to %p\n", idx, render_target);
6057
6058     if (rtimpl) {
6059         attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6060         This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6061     } else {
6062         GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6063         checkGLcall("glFramebufferTexture2DEXT()");
6064
6065         This->draw_buffers[idx] = GL_NONE;
6066     }
6067 }
6068
6069 static void check_fbo_status(IWineD3DDevice *iface) {
6070     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6071     GLenum status;
6072
6073     status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6074     if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6075         TRACE("FBO complete\n");
6076     } else {
6077         FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6078
6079         /* Dump the FBO attachments */
6080         if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6081             IWineD3DSurfaceImpl *attachment;
6082             int i;
6083
6084             for (i = 0; i < GL_LIMITS(buffers); ++i) {
6085                 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6086                 if (attachment) {
6087                     FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6088                             attachment->pow2Width, attachment->pow2Height);
6089                 }
6090             }
6091             attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6092             if (attachment) {
6093                 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6094                         attachment->pow2Width, attachment->pow2Height);
6095             }
6096         }
6097     }
6098 }
6099
6100 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6101     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6102     IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6103     IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6104
6105     if (!ds_impl) return FALSE;
6106
6107     if (ds_impl->current_renderbuffer) {
6108         return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6109                 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6110     }
6111
6112     return (rt_impl->pow2Width != ds_impl->pow2Width ||
6113             rt_impl->pow2Height != ds_impl->pow2Height);
6114 }
6115
6116 void apply_fbo_state(IWineD3DDevice *iface) {
6117     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6118     unsigned int i;
6119
6120     if (This->render_offscreen) {
6121         bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6122
6123         /* Apply render targets */
6124         for (i = 0; i < GL_LIMITS(buffers); ++i) {
6125             IWineD3DSurface *render_target = This->render_targets[i];
6126             if (This->fbo_color_attachments[i] != render_target) {
6127                 set_render_target_fbo(iface, i, render_target);
6128                 This->fbo_color_attachments[i] = render_target;
6129             }
6130         }
6131
6132         /* Apply depth targets */
6133         if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6134             unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6135             unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6136
6137             if (This->stencilBufferTarget) {
6138                 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6139             }
6140             set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6141             This->fbo_depth_attachment = This->stencilBufferTarget;
6142         }
6143
6144         if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6145             GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6146             checkGLcall("glDrawBuffers()");
6147         } else {
6148             glDrawBuffer(This->draw_buffers[0]);
6149             checkGLcall("glDrawBuffer()");
6150         }
6151     } else {
6152         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6153     }
6154
6155     check_fbo_status(iface);
6156 }
6157
6158 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6159         IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6160     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6161     GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6162     IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6163     GLenum gl_filter;
6164
6165     TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6166             This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6167     TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6168     TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6169
6170     switch (filter) {
6171         case WINED3DTEXF_LINEAR:
6172             gl_filter = GL_LINEAR;
6173             break;
6174
6175         default:
6176             FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6177         case WINED3DTEXF_NONE:
6178         case WINED3DTEXF_POINT:
6179             gl_filter = GL_NEAREST;
6180             break;
6181     }
6182
6183     /* Attach src surface to src fbo */
6184     src_swapchain = get_swapchain(src_surface);
6185     if (src_swapchain) {
6186         GLenum buffer;
6187
6188         TRACE("Source surface %p is onscreen\n", src_surface);
6189         ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6190
6191         ENTER_GL();
6192         GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6193         buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6194         glReadBuffer(buffer);
6195         checkGLcall("glReadBuffer()");
6196
6197         src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6198         src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6199     } else {
6200         TRACE("Source surface %p is offscreen\n", src_surface);
6201         ENTER_GL();
6202         bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6203         attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6204         glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6205         checkGLcall("glReadBuffer()");
6206     }
6207     LEAVE_GL();
6208
6209     /* Attach dst surface to dst fbo */
6210     dst_swapchain = get_swapchain(dst_surface);
6211     if (dst_swapchain) {
6212         GLenum buffer;
6213
6214         TRACE("Destination surface %p is onscreen\n", dst_surface);
6215         ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6216
6217         ENTER_GL();
6218         GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6219         buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6220         glDrawBuffer(buffer);
6221         checkGLcall("glDrawBuffer()");
6222
6223         dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6224         dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6225     } else {
6226         TRACE("Destination surface %p is offscreen\n", dst_surface);
6227
6228         /* No src or dst swapchain? Make sure some context is active(multithreading) */
6229         if(!src_swapchain) {
6230             ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6231         }
6232
6233         ENTER_GL();
6234         bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6235         attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6236         glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6237         checkGLcall("glDrawBuffer()");
6238     }
6239     glDisable(GL_SCISSOR_TEST);
6240     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6241
6242     if (flip) {
6243         GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6244                 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6245         checkGLcall("glBlitFramebuffer()");
6246     } else {
6247         GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6248                 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6249         checkGLcall("glBlitFramebuffer()");
6250     }
6251
6252     if (This->render_offscreen) {
6253         bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6254     } else {
6255         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6256         checkGLcall("glBindFramebuffer()");
6257     }
6258
6259     /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6260     if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6261             && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6262         glDrawBuffer(GL_BACK);
6263         checkGLcall("glDrawBuffer()");
6264     }
6265     LEAVE_GL();
6266 }
6267
6268 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6269     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6270     WINED3DVIEWPORT viewport;
6271
6272     TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6273
6274     if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6275         ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6276         return WINED3DERR_INVALIDCALL;
6277     }
6278
6279     /* MSDN says that null disables the render target
6280     but a device must always be associated with a render target
6281     nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6282
6283     see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6284     for more details
6285     */
6286     if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6287         FIXME("Trying to set render target 0 to NULL\n");
6288         return WINED3DERR_INVALIDCALL;
6289     }
6290     if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6291         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);
6292         return WINED3DERR_INVALIDCALL;
6293     }
6294
6295     /* If we are trying to set what we already have, don't bother */
6296     if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6297         TRACE("Trying to do a NOP SetRenderTarget operation\n");
6298         return WINED3D_OK;
6299     }
6300     if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6301     if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6302     This->render_targets[RenderTargetIndex] = pRenderTarget;
6303
6304     /* Render target 0 is special */
6305     if(RenderTargetIndex == 0) {
6306         /* Finally, reset the viewport as the MSDN states. */
6307         viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6308         viewport.Width  = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6309         viewport.X      = 0;
6310         viewport.Y      = 0;
6311         viewport.MaxZ   = 1.0f;
6312         viewport.MinZ   = 0.0f;
6313         IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6314         /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6315          * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6316          */
6317         IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6318
6319         /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6320          * ctx properly.
6321          * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6322          * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6323          */
6324         ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6325     }
6326     return WINED3D_OK;
6327 }
6328
6329 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6330     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6331     HRESULT  hr = WINED3D_OK;
6332     IWineD3DSurface *tmp;
6333
6334     TRACE("(%p) Swapping z-buffer\n",This);
6335
6336     if (pNewZStencil == This->stencilBufferTarget) {
6337         TRACE("Trying to do a NOP SetRenderTarget operation\n");
6338     } else {
6339         /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6340         * depending on the renter target implementation being used.
6341         * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6342         * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6343         * stencil buffer and incure an extra memory overhead
6344          ******************************************************/
6345
6346         tmp = This->stencilBufferTarget;
6347         This->stencilBufferTarget = pNewZStencil;
6348         This->depth_copy_state = WINED3D_DCS_NO_COPY;
6349         /* should we be calling the parent or the wined3d surface? */
6350         if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6351         if (NULL != tmp) IWineD3DSurface_Release(tmp);
6352         hr = WINED3D_OK;
6353
6354         if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6355             /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6356             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6357             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6358             IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6359         }
6360     }
6361
6362     return hr;
6363 }
6364
6365 static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6366                                                         UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6367     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6368     /* TODO: the use of Impl is deprecated. */
6369     IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6370     WINED3DLOCKED_RECT lockedRect;
6371
6372     TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6373
6374     /* some basic validation checks */
6375     if(This->cursorTexture) {
6376         ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6377         ENTER_GL();
6378         glDeleteTextures(1, &This->cursorTexture);
6379         LEAVE_GL();
6380         This->cursorTexture = 0;
6381     }
6382
6383     if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6384         This->haveHardwareCursor = TRUE;
6385     else
6386         This->haveHardwareCursor = FALSE;
6387
6388     if(pCursorBitmap) {
6389         WINED3DLOCKED_RECT rect;
6390
6391         /* MSDN: Cursor must be A8R8G8B8 */
6392         if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6393             ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6394             return WINED3DERR_INVALIDCALL;
6395         }
6396
6397         /* MSDN: Cursor must be smaller than the display mode */
6398         if(pSur->currentDesc.Width > This->ddraw_width ||
6399            pSur->currentDesc.Height > This->ddraw_height) {
6400             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);
6401             return WINED3DERR_INVALIDCALL;
6402         }
6403
6404         if (!This->haveHardwareCursor) {
6405             /* TODO: MSDN: Cursor sizes must be a power of 2 */
6406
6407             /* Do not store the surface's pointer because the application may
6408              * release it after setting the cursor image. Windows doesn't
6409              * addref the set surface, so we can't do this either without
6410              * creating circular refcount dependencies. Copy out the gl texture
6411              * instead.
6412              */
6413             This->cursorWidth = pSur->currentDesc.Width;
6414             This->cursorHeight = pSur->currentDesc.Height;
6415             if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6416             {
6417                 const GlPixelFormatDesc *glDesc;
6418                 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6419                 char *mem, *bits = (char *)rect.pBits;
6420                 GLint intfmt = glDesc->glInternal;
6421                 GLint format = glDesc->glFormat;
6422                 GLint type = glDesc->glType;
6423                 INT height = This->cursorHeight;
6424                 INT width = This->cursorWidth;
6425                 INT bpp = tableEntry->bpp;
6426                 INT i;
6427
6428                 /* Reformat the texture memory (pitch and width can be
6429                  * different) */
6430                 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6431                 for(i = 0; i < height; i++)
6432                     memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6433                 IWineD3DSurface_UnlockRect(pCursorBitmap);
6434                 ENTER_GL();
6435
6436                 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6437                     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6438                     checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6439                 }
6440
6441                 /* Make sure that a proper texture unit is selected */
6442                 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6443                     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6444                     checkGLcall("glActiveTextureARB");
6445                 }
6446                 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6447                 /* Create a new cursor texture */
6448                 glGenTextures(1, &This->cursorTexture);
6449                 checkGLcall("glGenTextures");
6450                 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6451                 checkGLcall("glBindTexture");
6452                 /* Copy the bitmap memory into the cursor texture */
6453                 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6454                 HeapFree(GetProcessHeap(), 0, mem);
6455                 checkGLcall("glTexImage2D");
6456
6457                 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6458                     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6459                     checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6460                 }
6461
6462                 LEAVE_GL();
6463             }
6464             else
6465             {
6466                 FIXME("A cursor texture was not returned.\n");
6467                 This->cursorTexture = 0;
6468             }
6469         }
6470         else
6471         {
6472             /* Draw a hardware cursor */
6473             ICONINFO cursorInfo;
6474             HCURSOR cursor;
6475             /* Create and clear maskBits because it is not needed for
6476              * 32-bit cursors.  32x32 bits split into 32-bit chunks == 32
6477              * chunks. */
6478             DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6479                 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6480             IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6481                                          WINED3DLOCK_NO_DIRTY_UPDATE |
6482                                          WINED3DLOCK_READONLY
6483             );
6484             TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6485                   pSur->currentDesc.Height);
6486
6487             cursorInfo.fIcon = FALSE;
6488             cursorInfo.xHotspot = XHotSpot;
6489             cursorInfo.yHotspot = YHotSpot;
6490             cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6491                                               pSur->currentDesc.Height, 1,
6492                                               1, &maskBits);
6493             cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6494                                                pSur->currentDesc.Height, 1,
6495                                                32, lockedRect.pBits);
6496             IWineD3DSurface_UnlockRect(pCursorBitmap);
6497             /* Create our cursor and clean up. */
6498             cursor = CreateIconIndirect(&cursorInfo);
6499             SetCursor(cursor);
6500             if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6501             if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6502             if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6503             This->hardwareCursor = cursor;
6504             HeapFree(GetProcessHeap(), 0, maskBits);
6505         }
6506     }
6507
6508     This->xHotSpot = XHotSpot;
6509     This->yHotSpot = YHotSpot;
6510     return WINED3D_OK;
6511 }
6512
6513 static void     WINAPI  IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6514     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6515     TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6516
6517     This->xScreenSpace = XScreenSpace;
6518     This->yScreenSpace = YScreenSpace;
6519
6520     return;
6521
6522 }
6523
6524 static BOOL     WINAPI  IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6525     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6526     BOOL oldVisible = This->bCursorVisible;
6527     POINT pt;
6528
6529     TRACE("(%p) : visible(%d)\n", This, bShow);
6530
6531     /*
6532      * When ShowCursor is first called it should make the cursor appear at the OS's last
6533      * known cursor position.  Because of this, some applications just repetitively call
6534      * ShowCursor in order to update the cursor's position.  This behavior is undocumented.
6535      */
6536     GetCursorPos(&pt);
6537     This->xScreenSpace = pt.x;
6538     This->yScreenSpace = pt.y;
6539
6540     if (This->haveHardwareCursor) {
6541         This->bCursorVisible = bShow;
6542         if (bShow)
6543             SetCursor(This->hardwareCursor);
6544         else
6545             SetCursor(NULL);
6546     }
6547     else
6548     {
6549         if (This->cursorTexture)
6550             This->bCursorVisible = bShow;
6551     }
6552
6553     return oldVisible;
6554 }
6555
6556 static HRESULT  WINAPI  IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6557     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6558     TRACE("(%p) : state (%u)\n", This, This->state);
6559     /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6560     switch (This->state) {
6561     case WINED3D_OK:
6562         return WINED3D_OK;
6563     case WINED3DERR_DEVICELOST:
6564         {
6565             ResourceList *resourceList  = This->resources;
6566             while (NULL != resourceList) {
6567                 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6568                 return WINED3DERR_DEVICENOTRESET;
6569                 resourceList = resourceList->next;
6570             }
6571             return WINED3DERR_DEVICELOST;
6572         }
6573     case WINED3DERR_DRIVERINTERNALERROR:
6574         return WINED3DERR_DRIVERINTERNALERROR;
6575     }
6576
6577     /* Unknown state */
6578     return WINED3DERR_DRIVERINTERNALERROR;
6579 }
6580
6581
6582 static HRESULT  WINAPI  IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6583     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6584     /** FIXME: Resource tracking needs to be done,
6585     * The closes we can do to this is set the priorities of all managed textures low
6586     * and then reset them.
6587      ***********************************************************/
6588     FIXME("(%p) : stub\n", This);
6589     return WINED3D_OK;
6590 }
6591
6592 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6593     IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6594
6595     /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6596     if(surface->Flags & SFLAG_DIBSECTION) {
6597         /* Release the DC */
6598         SelectObject(surface->hDC, surface->dib.holdbitmap);
6599         DeleteDC(surface->hDC);
6600         /* Release the DIB section */
6601         DeleteObject(surface->dib.DIBsection);
6602         surface->dib.bitmap_data = NULL;
6603         surface->resource.allocatedMemory = NULL;
6604         surface->Flags &= ~SFLAG_DIBSECTION;
6605     }
6606     surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6607     surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6608     if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6609         surface->pow2Width = pPresentationParameters->BackBufferWidth;
6610         surface->pow2Height = pPresentationParameters->BackBufferHeight;
6611     } else {
6612         surface->pow2Width = surface->pow2Height = 1;
6613         while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6614         while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6615     }
6616     if(surface->glDescription.textureName) {
6617         ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6618         ENTER_GL();
6619         glDeleteTextures(1, &surface->glDescription.textureName);
6620         LEAVE_GL();
6621         surface->glDescription.textureName = 0;
6622         surface->Flags &= ~SFLAG_CLIENT;
6623     }
6624     if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6625        surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6626         surface->Flags |= SFLAG_NONPOW2;
6627     } else  {
6628         surface->Flags &= ~SFLAG_NONPOW2;
6629     }
6630     HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6631     surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6632 }
6633
6634 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6635     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6636     IWineD3DSwapChainImpl *swapchain;
6637     HRESULT hr;
6638     BOOL DisplayModeChanged = FALSE;
6639     WINED3DDISPLAYMODE mode;
6640     TRACE("(%p)\n", This);
6641
6642     hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6643     if(FAILED(hr)) {
6644         ERR("Failed to get the first implicit swapchain\n");
6645         return hr;
6646     }
6647
6648     /* Is it necessary to recreate the gl context? Actually every setting can be changed
6649      * on an existing gl context, so there's no real need for recreation.
6650      *
6651      * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6652      *
6653      * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6654      */
6655     TRACE("New params:\n");
6656     TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6657     TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6658     TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6659     TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6660     TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6661     TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6662     TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6663     TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6664     TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6665     TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6666     TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6667     TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6668     TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6669
6670     /* No special treatment of these parameters. Just store them */
6671     swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6672     swapchain->presentParms.Flags = pPresentationParameters->Flags;
6673     swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6674     swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6675
6676     /* What to do about these? */
6677     if(pPresentationParameters->BackBufferCount != 0 &&
6678         pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6679         ERR("Cannot change the back buffer count yet\n");
6680     }
6681     if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6682         pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6683         ERR("Cannot change the back buffer format yet\n");
6684     }
6685     if(pPresentationParameters->hDeviceWindow != NULL &&
6686         pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6687         ERR("Cannot change the device window yet\n");
6688     }
6689     if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6690         ERR("What do do about a changed auto depth stencil parameter?\n");
6691     }
6692
6693     if(pPresentationParameters->Windowed) {
6694         mode.Width = swapchain->orig_width;
6695         mode.Height = swapchain->orig_height;
6696         mode.RefreshRate = 0;
6697         mode.Format = swapchain->presentParms.BackBufferFormat;
6698     } else {
6699         mode.Width = pPresentationParameters->BackBufferWidth;
6700         mode.Height = pPresentationParameters->BackBufferHeight;
6701         mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6702         mode.Format = swapchain->presentParms.BackBufferFormat;
6703     }
6704
6705     /* Should Width == 800 && Height == 0 set 800x600? */
6706     if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6707        (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6708         pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6709     {
6710         WINED3DVIEWPORT vp;
6711         int i;
6712
6713         vp.X = 0;
6714         vp.Y = 0;
6715         vp.Width = pPresentationParameters->BackBufferWidth;
6716         vp.Height = pPresentationParameters->BackBufferHeight;
6717         vp.MinZ = 0;
6718         vp.MaxZ = 1;
6719
6720         if(!pPresentationParameters->Windowed) {
6721             DisplayModeChanged = TRUE;
6722         }
6723         swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6724         swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6725
6726         updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6727         for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6728             updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6729         }
6730
6731         /* Now set the new viewport */
6732         IWineD3DDevice_SetViewport(iface, &vp);
6733     }
6734
6735     if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6736        (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6737         DisplayModeChanged) {
6738
6739         /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6740         if(!pPresentationParameters->Windowed) {
6741             IWineD3DDevice_SetFullscreen(iface, TRUE);
6742         }
6743
6744         IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6745
6746         /* Switching out of fullscreen mode? First set the original res, then change the window */
6747         if(pPresentationParameters->Windowed) {
6748             IWineD3DDevice_SetFullscreen(iface, FALSE);
6749         }
6750         swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6751     }
6752
6753     IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6754     return WINED3D_OK;
6755 }
6756
6757 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6758     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6759     /** FIXME: always true at the moment **/
6760     if(!bEnableDialogs) {
6761         FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6762     }
6763     return WINED3D_OK;
6764 }
6765
6766
6767 static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6768     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6769     TRACE("(%p) : pParameters %p\n", This, pParameters);
6770
6771     *pParameters = This->createParms;
6772     return WINED3D_OK;
6773 }
6774
6775 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6776     IWineD3DSwapChain *swapchain;
6777     HRESULT hrc = WINED3D_OK;
6778
6779     TRACE("Relaying  to swapchain\n");
6780
6781     if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6782         IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6783         IWineD3DSwapChain_Release(swapchain);
6784     }
6785     return;
6786 }
6787
6788 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6789     IWineD3DSwapChain *swapchain;
6790     HRESULT hrc = WINED3D_OK;
6791
6792     TRACE("Relaying  to swapchain\n");
6793
6794     if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6795         hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6796         IWineD3DSwapChain_Release(swapchain);
6797     }
6798     return;
6799 }
6800
6801
6802 /** ********************************************************
6803 *   Notification functions
6804 ** ********************************************************/
6805 /** This function must be called in the release of a resource when ref == 0,
6806 * the contents of resource must still be correct,
6807 * any handels to other resource held by the caller must be closed
6808 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6809  *****************************************************/
6810 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6811     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6812     ResourceList* resourceList;
6813
6814     TRACE("(%p) : resource %p\n", This, resource);
6815     /* add a new texture to the frot of the linked list */
6816     resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6817     resourceList->resource = resource;
6818
6819     /* Get the old head */
6820     resourceList->next = This->resources;
6821
6822     This->resources = resourceList;
6823     TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6824
6825     return;
6826 }
6827
6828 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6829     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6830     ResourceList* resourceList = NULL;
6831     ResourceList* previousResourceList = NULL;
6832     
6833     TRACE("(%p) : resource %p\n", This, resource);
6834
6835     resourceList = This->resources;
6836
6837     while (resourceList != NULL) {
6838         if(resourceList->resource == resource) break;
6839         previousResourceList = resourceList;
6840         resourceList = resourceList->next;
6841     }
6842
6843     if (resourceList == NULL) {
6844         FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6845         return;
6846     } else {
6847             TRACE("Found resource  %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6848     }
6849     /* make sure we don't leave a hole in the list */
6850     if (previousResourceList != NULL) {
6851         previousResourceList->next = resourceList->next;
6852     } else {
6853         This->resources = resourceList->next;
6854     }
6855
6856     return;
6857 }
6858
6859
6860 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6861     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6862     int counter;
6863
6864     TRACE("(%p) : resource %p\n", This, resource);
6865     switch(IWineD3DResource_GetType(resource)){
6866         /* TODO: check front and back buffers, rendertargets etc..  possibly swapchains? */
6867         case WINED3DRTYPE_SURFACE: {
6868             unsigned int i;
6869
6870             /* Cleanup any FBO attachments if d3d is enabled */
6871             if(This->d3d_initialized) {
6872                 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6873                     if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6874                         bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6875                         set_render_target_fbo(iface, i, NULL);
6876                         This->fbo_color_attachments[i] = NULL;
6877                     }
6878                 }
6879                 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6880                     bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6881                     set_depth_stencil_fbo(iface, NULL);
6882                     This->fbo_depth_attachment = NULL;
6883                 }
6884             }
6885
6886             break;
6887         }
6888         case WINED3DRTYPE_TEXTURE:
6889         case WINED3DRTYPE_CUBETEXTURE:
6890         case WINED3DRTYPE_VOLUMETEXTURE:
6891                 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6892                     if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6893                         WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6894                         This->stateBlock->textures[counter] = NULL;
6895                     }
6896                     if (This->updateStateBlock != This->stateBlock ){
6897                         if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6898                             WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6899                             This->updateStateBlock->textures[counter] = NULL;
6900                         }
6901                     }
6902                 }
6903         break;
6904         case WINED3DRTYPE_VOLUME:
6905         /* TODO: nothing really? */
6906         break;
6907         case WINED3DRTYPE_VERTEXBUFFER:
6908         /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6909         {
6910             int streamNumber;
6911             TRACE("Cleaning up stream pointers\n");
6912
6913             for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6914                 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6915                 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6916                 */
6917                 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6918                     if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6919                         FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6920                         This->updateStateBlock->streamSource[streamNumber] = 0;
6921                         /* Set changed flag? */
6922                     }
6923                 }
6924                 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) */
6925                     if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6926                         TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6927                         This->stateBlock->streamSource[streamNumber] = 0;
6928                     }
6929                 }
6930 #if 0   /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6931                  else { /* This shouldn't happen */
6932                     FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6933                 }
6934 #endif
6935
6936             }
6937         }
6938         break;
6939         case WINED3DRTYPE_INDEXBUFFER:
6940         /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6941         if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6942             if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6943                 This->updateStateBlock->pIndexData =  NULL;
6944             }
6945         }
6946         if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6947             if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6948                 This->stateBlock->pIndexData =  NULL;
6949             }
6950         }
6951
6952         break;
6953         default:
6954         FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6955         break;
6956     }
6957
6958
6959     /* Remove the resoruce from the resourceStore */
6960     IWineD3DDeviceImpl_RemoveResource(iface, resource);
6961
6962     TRACE("Resource released\n");
6963
6964 }
6965
6966 /**********************************************************
6967  * IWineD3DDevice VTbl follows
6968  **********************************************************/
6969
6970 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6971 {
6972     /*** IUnknown methods ***/
6973     IWineD3DDeviceImpl_QueryInterface,
6974     IWineD3DDeviceImpl_AddRef,
6975     IWineD3DDeviceImpl_Release,
6976     /*** IWineD3DDevice methods ***/
6977     IWineD3DDeviceImpl_GetParent,
6978     /*** Creation methods**/
6979     IWineD3DDeviceImpl_CreateVertexBuffer,
6980     IWineD3DDeviceImpl_CreateIndexBuffer,
6981     IWineD3DDeviceImpl_CreateStateBlock,
6982     IWineD3DDeviceImpl_CreateSurface,
6983     IWineD3DDeviceImpl_CreateTexture,
6984     IWineD3DDeviceImpl_CreateVolumeTexture,
6985     IWineD3DDeviceImpl_CreateVolume,
6986     IWineD3DDeviceImpl_CreateCubeTexture,
6987     IWineD3DDeviceImpl_CreateQuery,
6988     IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6989     IWineD3DDeviceImpl_CreateVertexDeclaration,
6990     IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6991     IWineD3DDeviceImpl_CreateVertexShader,
6992     IWineD3DDeviceImpl_CreatePixelShader,
6993     IWineD3DDeviceImpl_CreatePalette,
6994     /*** Odd functions **/
6995     IWineD3DDeviceImpl_Init3D,
6996     IWineD3DDeviceImpl_Uninit3D,
6997     IWineD3DDeviceImpl_SetFullscreen,
6998     IWineD3DDeviceImpl_SetMultithreaded,
6999     IWineD3DDeviceImpl_EvictManagedResources,
7000     IWineD3DDeviceImpl_GetAvailableTextureMem,
7001     IWineD3DDeviceImpl_GetBackBuffer,
7002     IWineD3DDeviceImpl_GetCreationParameters,
7003     IWineD3DDeviceImpl_GetDeviceCaps,
7004     IWineD3DDeviceImpl_GetDirect3D,
7005     IWineD3DDeviceImpl_GetDisplayMode,
7006     IWineD3DDeviceImpl_SetDisplayMode,
7007     IWineD3DDeviceImpl_GetHWND,
7008     IWineD3DDeviceImpl_SetHWND,
7009     IWineD3DDeviceImpl_GetNumberOfSwapChains,
7010     IWineD3DDeviceImpl_GetRasterStatus,
7011     IWineD3DDeviceImpl_GetSwapChain,
7012     IWineD3DDeviceImpl_Reset,
7013     IWineD3DDeviceImpl_SetDialogBoxMode,
7014     IWineD3DDeviceImpl_SetCursorProperties,
7015     IWineD3DDeviceImpl_SetCursorPosition,
7016     IWineD3DDeviceImpl_ShowCursor,
7017     IWineD3DDeviceImpl_TestCooperativeLevel,
7018     /*** Getters and setters **/
7019     IWineD3DDeviceImpl_SetClipPlane,
7020     IWineD3DDeviceImpl_GetClipPlane,
7021     IWineD3DDeviceImpl_SetClipStatus,
7022     IWineD3DDeviceImpl_GetClipStatus,
7023     IWineD3DDeviceImpl_SetCurrentTexturePalette,
7024     IWineD3DDeviceImpl_GetCurrentTexturePalette,
7025     IWineD3DDeviceImpl_SetDepthStencilSurface,
7026     IWineD3DDeviceImpl_GetDepthStencilSurface,
7027     IWineD3DDeviceImpl_SetFVF,
7028     IWineD3DDeviceImpl_GetFVF,
7029     IWineD3DDeviceImpl_SetGammaRamp,
7030     IWineD3DDeviceImpl_GetGammaRamp,
7031     IWineD3DDeviceImpl_SetIndices,
7032     IWineD3DDeviceImpl_GetIndices,
7033     IWineD3DDeviceImpl_SetBaseVertexIndex,
7034     IWineD3DDeviceImpl_GetBaseVertexIndex,
7035     IWineD3DDeviceImpl_SetLight,
7036     IWineD3DDeviceImpl_GetLight,
7037     IWineD3DDeviceImpl_SetLightEnable,
7038     IWineD3DDeviceImpl_GetLightEnable,
7039     IWineD3DDeviceImpl_SetMaterial,
7040     IWineD3DDeviceImpl_GetMaterial,
7041     IWineD3DDeviceImpl_SetNPatchMode,
7042     IWineD3DDeviceImpl_GetNPatchMode,
7043     IWineD3DDeviceImpl_SetPaletteEntries,
7044     IWineD3DDeviceImpl_GetPaletteEntries,
7045     IWineD3DDeviceImpl_SetPixelShader,
7046     IWineD3DDeviceImpl_GetPixelShader,
7047     IWineD3DDeviceImpl_SetPixelShaderConstantB,
7048     IWineD3DDeviceImpl_GetPixelShaderConstantB,
7049     IWineD3DDeviceImpl_SetPixelShaderConstantI,
7050     IWineD3DDeviceImpl_GetPixelShaderConstantI,
7051     IWineD3DDeviceImpl_SetPixelShaderConstantF,
7052     IWineD3DDeviceImpl_GetPixelShaderConstantF,
7053     IWineD3DDeviceImpl_SetRenderState,
7054     IWineD3DDeviceImpl_GetRenderState,
7055     IWineD3DDeviceImpl_SetRenderTarget,
7056     IWineD3DDeviceImpl_GetRenderTarget,
7057     IWineD3DDeviceImpl_SetFrontBackBuffers,
7058     IWineD3DDeviceImpl_SetSamplerState,
7059     IWineD3DDeviceImpl_GetSamplerState,
7060     IWineD3DDeviceImpl_SetScissorRect,
7061     IWineD3DDeviceImpl_GetScissorRect,
7062     IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7063     IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7064     IWineD3DDeviceImpl_SetStreamSource,
7065     IWineD3DDeviceImpl_GetStreamSource,
7066     IWineD3DDeviceImpl_SetStreamSourceFreq,
7067     IWineD3DDeviceImpl_GetStreamSourceFreq,
7068     IWineD3DDeviceImpl_SetTexture,
7069     IWineD3DDeviceImpl_GetTexture,
7070     IWineD3DDeviceImpl_SetTextureStageState,
7071     IWineD3DDeviceImpl_GetTextureStageState,
7072     IWineD3DDeviceImpl_SetTransform,
7073     IWineD3DDeviceImpl_GetTransform,
7074     IWineD3DDeviceImpl_SetVertexDeclaration,
7075     IWineD3DDeviceImpl_GetVertexDeclaration,
7076     IWineD3DDeviceImpl_SetVertexShader,
7077     IWineD3DDeviceImpl_GetVertexShader,
7078     IWineD3DDeviceImpl_SetVertexShaderConstantB,
7079     IWineD3DDeviceImpl_GetVertexShaderConstantB,
7080     IWineD3DDeviceImpl_SetVertexShaderConstantI,
7081     IWineD3DDeviceImpl_GetVertexShaderConstantI,
7082     IWineD3DDeviceImpl_SetVertexShaderConstantF,
7083     IWineD3DDeviceImpl_GetVertexShaderConstantF,
7084     IWineD3DDeviceImpl_SetViewport,
7085     IWineD3DDeviceImpl_GetViewport,
7086     IWineD3DDeviceImpl_MultiplyTransform,
7087     IWineD3DDeviceImpl_ValidateDevice,
7088     IWineD3DDeviceImpl_ProcessVertices,
7089     /*** State block ***/
7090     IWineD3DDeviceImpl_BeginStateBlock,
7091     IWineD3DDeviceImpl_EndStateBlock,
7092     /*** Scene management ***/
7093     IWineD3DDeviceImpl_BeginScene,
7094     IWineD3DDeviceImpl_EndScene,
7095     IWineD3DDeviceImpl_Present,
7096     IWineD3DDeviceImpl_Clear,
7097     /*** Drawing ***/
7098     IWineD3DDeviceImpl_DrawPrimitive,
7099     IWineD3DDeviceImpl_DrawIndexedPrimitive,
7100     IWineD3DDeviceImpl_DrawPrimitiveUP,
7101     IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7102     IWineD3DDeviceImpl_DrawPrimitiveStrided,
7103     IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7104     IWineD3DDeviceImpl_DrawRectPatch,
7105     IWineD3DDeviceImpl_DrawTriPatch,
7106     IWineD3DDeviceImpl_DeletePatch,
7107     IWineD3DDeviceImpl_ColorFill,
7108     IWineD3DDeviceImpl_UpdateTexture,
7109     IWineD3DDeviceImpl_UpdateSurface,
7110     IWineD3DDeviceImpl_GetFrontBufferData,
7111     /*** object tracking ***/
7112     IWineD3DDeviceImpl_ResourceReleased
7113 };
7114
7115
7116 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7117     WINED3DRS_ALPHABLENDENABLE   ,
7118     WINED3DRS_ALPHAFUNC          ,
7119     WINED3DRS_ALPHAREF           ,
7120     WINED3DRS_ALPHATESTENABLE    ,
7121     WINED3DRS_BLENDOP            ,
7122     WINED3DRS_COLORWRITEENABLE   ,
7123     WINED3DRS_DESTBLEND          ,
7124     WINED3DRS_DITHERENABLE       ,
7125     WINED3DRS_FILLMODE           ,
7126     WINED3DRS_FOGDENSITY         ,
7127     WINED3DRS_FOGEND             ,
7128     WINED3DRS_FOGSTART           ,
7129     WINED3DRS_LASTPIXEL          ,
7130     WINED3DRS_SHADEMODE          ,
7131     WINED3DRS_SRCBLEND           ,
7132     WINED3DRS_STENCILENABLE      ,
7133     WINED3DRS_STENCILFAIL        ,
7134     WINED3DRS_STENCILFUNC        ,
7135     WINED3DRS_STENCILMASK        ,
7136     WINED3DRS_STENCILPASS        ,
7137     WINED3DRS_STENCILREF         ,
7138     WINED3DRS_STENCILWRITEMASK   ,
7139     WINED3DRS_STENCILZFAIL       ,
7140     WINED3DRS_TEXTUREFACTOR      ,
7141     WINED3DRS_WRAP0              ,
7142     WINED3DRS_WRAP1              ,
7143     WINED3DRS_WRAP2              ,
7144     WINED3DRS_WRAP3              ,
7145     WINED3DRS_WRAP4              ,
7146     WINED3DRS_WRAP5              ,
7147     WINED3DRS_WRAP6              ,
7148     WINED3DRS_WRAP7              ,
7149     WINED3DRS_ZENABLE            ,
7150     WINED3DRS_ZFUNC              ,
7151     WINED3DRS_ZWRITEENABLE
7152 };
7153
7154 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7155     WINED3DTSS_ADDRESSW              ,
7156     WINED3DTSS_ALPHAARG0             ,
7157     WINED3DTSS_ALPHAARG1             ,
7158     WINED3DTSS_ALPHAARG2             ,
7159     WINED3DTSS_ALPHAOP               ,
7160     WINED3DTSS_BUMPENVLOFFSET        ,
7161     WINED3DTSS_BUMPENVLSCALE         ,
7162     WINED3DTSS_BUMPENVMAT00          ,
7163     WINED3DTSS_BUMPENVMAT01          ,
7164     WINED3DTSS_BUMPENVMAT10          ,
7165     WINED3DTSS_BUMPENVMAT11          ,
7166     WINED3DTSS_COLORARG0             ,
7167     WINED3DTSS_COLORARG1             ,
7168     WINED3DTSS_COLORARG2             ,
7169     WINED3DTSS_COLOROP               ,
7170     WINED3DTSS_RESULTARG             ,
7171     WINED3DTSS_TEXCOORDINDEX         ,
7172     WINED3DTSS_TEXTURETRANSFORMFLAGS
7173 };
7174
7175 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7176     WINED3DSAMP_ADDRESSU         ,
7177     WINED3DSAMP_ADDRESSV         ,
7178     WINED3DSAMP_ADDRESSW         ,
7179     WINED3DSAMP_BORDERCOLOR      ,
7180     WINED3DSAMP_MAGFILTER        ,
7181     WINED3DSAMP_MINFILTER        ,
7182     WINED3DSAMP_MIPFILTER        ,
7183     WINED3DSAMP_MIPMAPLODBIAS    ,
7184     WINED3DSAMP_MAXMIPLEVEL      ,
7185     WINED3DSAMP_MAXANISOTROPY    ,
7186     WINED3DSAMP_SRGBTEXTURE      ,
7187     WINED3DSAMP_ELEMENTINDEX
7188 };
7189
7190 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7191     WINED3DRS_AMBIENT                       ,
7192     WINED3DRS_AMBIENTMATERIALSOURCE         ,
7193     WINED3DRS_CLIPPING                      ,
7194     WINED3DRS_CLIPPLANEENABLE               ,
7195     WINED3DRS_COLORVERTEX                   ,
7196     WINED3DRS_DIFFUSEMATERIALSOURCE         ,
7197     WINED3DRS_EMISSIVEMATERIALSOURCE        ,
7198     WINED3DRS_FOGDENSITY                    ,
7199     WINED3DRS_FOGEND                        ,
7200     WINED3DRS_FOGSTART                      ,
7201     WINED3DRS_FOGTABLEMODE                  ,
7202     WINED3DRS_FOGVERTEXMODE                 ,
7203     WINED3DRS_INDEXEDVERTEXBLENDENABLE      ,
7204     WINED3DRS_LIGHTING                      ,
7205     WINED3DRS_LOCALVIEWER                   ,
7206     WINED3DRS_MULTISAMPLEANTIALIAS          ,
7207     WINED3DRS_MULTISAMPLEMASK               ,
7208     WINED3DRS_NORMALIZENORMALS              ,
7209     WINED3DRS_PATCHEDGESTYLE                ,
7210     WINED3DRS_POINTSCALE_A                  ,
7211     WINED3DRS_POINTSCALE_B                  ,
7212     WINED3DRS_POINTSCALE_C                  ,
7213     WINED3DRS_POINTSCALEENABLE              ,
7214     WINED3DRS_POINTSIZE                     ,
7215     WINED3DRS_POINTSIZE_MAX                 ,
7216     WINED3DRS_POINTSIZE_MIN                 ,
7217     WINED3DRS_POINTSPRITEENABLE             ,
7218     WINED3DRS_RANGEFOGENABLE                ,
7219     WINED3DRS_SPECULARMATERIALSOURCE        ,
7220     WINED3DRS_TWEENFACTOR                   ,
7221     WINED3DRS_VERTEXBLEND                   ,
7222     WINED3DRS_CULLMODE                      ,
7223     WINED3DRS_FOGCOLOR
7224 };
7225
7226 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7227     WINED3DTSS_TEXCOORDINDEX         ,
7228     WINED3DTSS_TEXTURETRANSFORMFLAGS
7229 };
7230
7231 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7232     WINED3DSAMP_DMAPOFFSET
7233 };
7234
7235 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7236     DWORD rep = StateTable[state].representative;
7237     DWORD idx;
7238     BYTE shift;
7239     UINT i;
7240     WineD3DContext *context;
7241
7242     if(!rep) return;
7243     for(i = 0; i < This->numContexts; i++) {
7244         context = This->contexts[i];
7245         if(isStateDirty(context, rep)) continue;
7246
7247         context->dirtyArray[context->numDirtyEntries++] = rep;
7248         idx = rep >> 5;
7249         shift = rep & 0x1f;
7250         context->isStateDirty[idx] |= (1 << shift);
7251     }
7252 }