2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * GLSL helper functions follow
153 **********************************************************/
155 /** Detach the GLSL pixel or vertex shader object from the shader program */
156 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 if (shaderObj != 0 && programId != 0) {
161 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
162 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
163 checkGLcall("glDetachObjectARB");
167 /** Delete a GLSL shader program */
168 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
173 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
174 GL_EXTCALL(glDeleteObjectARB(obj));
175 checkGLcall("glDeleteObjectARB");
179 /** Delete the list of linked programs this shader is associated with.
180 * Also at this point, check to see if there are any objects left attached
181 * to each GLSL program. If not, delete the GLSL program object.
182 * This will be run when a device is released. */
183 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
185 struct list *ptr = NULL;
186 struct glsl_shader_prog_link *curLink = NULL;
187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
191 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
192 (one pixel shader and one vertex shader at most) */
194 ptr = list_head( &This->glsl_shader_progs );
196 /* First, get the current item,
197 * save the link to the next pointer,
198 * detach and delete shader objects,
199 * then de-allocate the list item's memory */
200 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
201 ptr = list_next( &This->glsl_shader_progs, ptr );
203 /* See if this object is still attached to the program - it may have been detached already */
204 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
205 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
206 for (i = 0; i < numAttached; i++) {
207 detach_glsl_shader(iface, objList[i], curLink->programId);
210 delete_glsl_shader_program(iface, curLink->programId);
212 /* Free the uniform locations */
213 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
214 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
216 /* Free the memory for this list item */
217 HeapFree(GetProcessHeap(), 0, curLink);
221 /**********************************************************
222 * IUnknown parts follows
223 **********************************************************/
225 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
229 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
230 if (IsEqualGUID(riid, &IID_IUnknown)
231 || IsEqualGUID(riid, &IID_IWineD3DBase)
232 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
233 IUnknown_AddRef(iface);
238 return E_NOINTERFACE;
241 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
243 ULONG refCount = InterlockedIncrement(&This->ref);
245 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
249 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 ULONG refCount = InterlockedDecrement(&This->ref);
253 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
257 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
260 HeapFree(GetProcessHeap(), 0, This->render_targets);
262 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
264 /* TODO: Clean up all the surfaces and textures! */
265 /* NOTE: You must release the parent if the object was created via a callback
266 ** ***************************/
268 /* Delete any GLSL shader programs that may exist */
269 if (This->vs_selected_mode == SHADER_GLSL ||
270 This->ps_selected_mode == SHADER_GLSL)
271 delete_glsl_shader_list(iface);
273 /* Release the update stateblock */
274 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
275 if(This->updateStateBlock != This->stateBlock)
276 FIXME("(%p) Something's still holding the Update stateblock\n",This);
278 This->updateStateBlock = NULL;
279 { /* because were not doing proper internal refcounts releasing the primary state block
280 causes recursion with the extra checks in ResourceReleased, to avoid this we have
281 to set this->stateBlock = NULL; first */
282 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
283 This->stateBlock = NULL;
285 /* Release the stateblock */
286 if(IWineD3DStateBlock_Release(stateBlock) > 0){
287 FIXME("(%p) Something's still holding the Update stateblock\n",This);
291 if (This->resources != NULL ) {
292 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
293 dumpResources(This->resources);
296 if(This->contexts) ERR("Context array not freed!\n");
298 IWineD3D_Release(This->wineD3D);
299 This->wineD3D = NULL;
300 HeapFree(GetProcessHeap(), 0, This);
301 TRACE("Freed device %p\n", This);
307 /**********************************************************
308 * IWineD3DDevice implementation follows
309 **********************************************************/
310 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 *pParent = This->parent;
313 IUnknown_AddRef(This->parent);
317 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
318 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
319 GLenum error, glUsage;
320 DWORD vboUsage = object->resource.usage;
321 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
322 WARN("Creating a vbo failed once, not trying again\n");
326 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
329 /* Make sure that the gl error is cleared. Do not use checkGLcall
330 * here because checkGLcall just prints a fixme and continues. However,
331 * if an error during VBO creation occurs we can fall back to non-vbo operation
332 * with full functionality(but performance loss)
334 while(glGetError() != GL_NO_ERROR);
336 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
337 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
338 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
339 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
340 * to check if the rhw and color values are in the correct format.
343 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
344 error = glGetError();
345 if(object->vbo == 0 || error != GL_NO_ERROR) {
346 WARN("Failed to create a VBO with error %d\n", error);
350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
351 error = glGetError();
352 if(error != GL_NO_ERROR) {
353 WARN("Failed to bind the VBO, error %d\n", error);
357 /* Don't use static, because dx apps tend to update the buffer
358 * quite often even if they specify 0 usage. Because we always keep the local copy
359 * we never read from the vbo and can create a write only opengl buffer.
361 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
362 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
363 case WINED3DUSAGE_DYNAMIC:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage = GL_STREAM_DRAW_ARB;
367 case WINED3DUSAGE_WRITEONLY:
369 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
370 glUsage = GL_DYNAMIC_DRAW_ARB;
374 /* Reserve memory for the buffer. The amount of data won't change
375 * so we are safe with calling glBufferData once with a NULL ptr and
376 * calling glBufferSubData on updates
378 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
379 error = glGetError();
380 if(error != GL_NO_ERROR) {
381 WARN("glBufferDataARB failed with error %d\n", error);
389 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
390 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
391 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
393 object->Flags |= VBFLAG_VBOCREATEFAIL;
398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
399 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 IWineD3DVertexBufferImpl *object;
403 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
404 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
408 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
409 *ppVertexBuffer = NULL;
410 return WINED3DERR_INVALIDCALL;
413 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
415 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
416 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
418 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
419 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
423 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
424 * drawStridedFast (half-life 2).
426 * Basically converting the vertices in the buffer is quite expensive, and observations
427 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
428 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
430 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
431 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
432 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
433 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
435 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
436 * more. In this call we can convert dx7 buffers too.
438 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
439 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
440 (dxVersion > 7 || !conv) ) {
446 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
447 GLenum error, glUsage;
448 TRACE("Creating VBO for Index Buffer %p\n", object);
453 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
454 error = glGetError();
455 if(error != GL_NO_ERROR || object->vbo == 0) {
456 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
461 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
462 error = glGetError();
463 if(error != GL_NO_ERROR) {
464 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
468 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
469 * copy no readback will be needed
471 glUsage = GL_STATIC_DRAW;
472 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
473 error = glGetError();
474 if(error != GL_NO_ERROR) {
475 ERR("Failed to initialize the index buffer\n");
479 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
483 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
484 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
490 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
491 HANDLE *sharedHandle, IUnknown *parent) {
492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
493 IWineD3DIndexBufferImpl *object;
494 TRACE("(%p) Creating index buffer\n", This);
496 /* Allocate the storage for the device */
497 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
499 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
500 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
503 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
504 CreateIndexBufferVBO(This, object);
507 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
508 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
509 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
517 IWineD3DStateBlockImpl *object;
521 D3DCREATEOBJECTINSTANCE(object, StateBlock)
522 object->blockType = Type;
524 for(i = 0; i < LIGHTMAP_SIZE; i++) {
525 list_init(&object->lightMap[i]);
528 /* Special case - Used during initialization to produce a placeholder stateblock
529 so other functions called can update a state block */
530 if (Type == WINED3DSBT_INIT) {
531 /* Don't bother increasing the reference count otherwise a device will never
532 be freed due to circular dependencies */
536 temp_result = allocate_shader_constants(object);
537 if (WINED3D_OK != temp_result)
540 /* Otherwise, might as well set the whole state block to the appropriate values */
541 if (This->stateBlock != NULL)
542 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
544 memset(object->streamFreq, 1, sizeof(object->streamFreq));
546 /* Reset the ref and type after kludging it */
547 object->wineD3DDevice = This;
549 object->blockType = Type;
551 TRACE("Updating changed flags appropriate for type %d\n", Type);
553 if (Type == WINED3DSBT_ALL) {
555 TRACE("ALL => Pretend everything has changed\n");
556 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
558 /* Lights are not part of the changed / set structure */
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
567 } else if (Type == WINED3DSBT_PIXELSTATE) {
569 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
570 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
572 object->changed.pixelShader = TRUE;
574 /* Pixel Shader Constants */
575 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
576 object->changed.pixelShaderConstantsF[i] = TRUE;
577 for (i = 0; i < MAX_CONST_B; ++i)
578 object->changed.pixelShaderConstantsB[i] = TRUE;
579 for (i = 0; i < MAX_CONST_I; ++i)
580 object->changed.pixelShaderConstantsI[i] = TRUE;
582 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
583 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
585 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
586 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
587 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
590 for (j = 0 ; j < 16; j++) {
591 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
593 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
597 } else if (Type == WINED3DSBT_VERTEXSTATE) {
599 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
600 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
602 object->changed.vertexShader = TRUE;
604 /* Vertex Shader Constants */
605 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
606 object->changed.vertexShaderConstantsF[i] = TRUE;
607 for (i = 0; i < MAX_CONST_B; ++i)
608 object->changed.vertexShaderConstantsB[i] = TRUE;
609 for (i = 0; i < MAX_CONST_I; ++i)
610 object->changed.vertexShaderConstantsI[i] = TRUE;
612 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
613 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
616 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
617 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
620 for (j = 0 ; j < 16; j++){
621 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
622 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
626 for(j = 0; j < LIGHTMAP_SIZE; j++) {
628 LIST_FOR_EACH(e, &object->lightMap[j]) {
629 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
630 light->changed = TRUE;
631 light->enabledChanged = TRUE;
635 FIXME("Unrecognized state block type %d\n", Type);
638 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
643 /* ************************************
645 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
648 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
650 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.
652 ******************************** */
654 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) {
655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
656 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
657 unsigned int pow2Width, pow2Height;
658 unsigned int Size = 1;
659 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
660 TRACE("(%p) Create surface\n",This);
662 /** FIXME: Check ranges on the inputs are valid
665 * [in] Quality level. The valid range is between zero and one less than the level
666 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
667 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
668 * values of paired render targets, depth stencil surfaces, and the MultiSample type
670 *******************************/
675 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
677 * If this flag is set, the contents of the depth stencil buffer will be
678 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
679 * with a different depth surface.
681 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
682 ***************************/
684 if(MultisampleQuality < 0) {
685 FIXME("Invalid multisample level %d\n", MultisampleQuality);
686 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
689 if(MultisampleQuality > 0) {
690 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
691 MultisampleQuality=0;
694 /** FIXME: Check that the format is supported
696 *******************************/
698 /* Non-power2 support */
699 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
703 /* Find the nearest pow2 match */
704 pow2Width = pow2Height = 1;
705 while (pow2Width < Width) pow2Width <<= 1;
706 while (pow2Height < Height) pow2Height <<= 1;
709 if (pow2Width > Width || pow2Height > Height) {
710 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
711 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
712 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
713 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
714 This, Width, Height);
715 return WINED3DERR_NOTAVAILABLE;
719 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
720 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
722 *********************************/
723 if (WINED3DFMT_UNKNOWN == Format) {
725 } else if (Format == WINED3DFMT_DXT1) {
726 /* DXT1 is half byte per pixel */
727 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
729 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
730 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
731 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
733 /* The pitch is a multiple of 4 bytes */
734 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
738 /** Create and initialise the surface resource **/
739 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
740 /* "Standalone" surface */
741 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
743 object->currentDesc.Width = Width;
744 object->currentDesc.Height = Height;
745 object->currentDesc.MultiSampleType = MultiSample;
746 object->currentDesc.MultiSampleQuality = MultisampleQuality;
748 /* Setup some glformat defaults */
749 object->glDescription.glFormat = tableEntry->glFormat;
750 object->glDescription.glFormatInternal = tableEntry->glInternal;
751 object->glDescription.glType = tableEntry->glType;
753 object->glDescription.textureName = 0;
754 object->glDescription.level = Level;
755 object->glDescription.target = GL_TEXTURE_2D;
758 object->pow2Width = pow2Width;
759 object->pow2Height = pow2Height;
762 object->Flags = 0; /* We start without flags set */
763 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
764 object->Flags |= Discard ? SFLAG_DISCARD : 0;
765 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
766 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
769 if (WINED3DFMT_UNKNOWN != Format) {
770 object->bytesPerPixel = tableEntry->bpp;
772 object->bytesPerPixel = 0;
775 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
777 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
779 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
780 * this function is too deep to need to care about things like this.
781 * Levels need to be checked too, and possibly Type since they all affect what can be done.
782 * ****************************************/
784 case WINED3DPOOL_SCRATCH:
786 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
787 "which are mutually exclusive, setting lockable to TRUE\n");
790 case WINED3DPOOL_SYSTEMMEM:
791 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
792 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
793 case WINED3DPOOL_MANAGED:
794 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
795 "Usage of DYNAMIC which are mutually exclusive, not doing "
796 "anything just telling you.\n");
798 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
799 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
800 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
801 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
804 FIXME("(%p) Unknown pool %d\n", This, Pool);
808 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
809 FIXME("Trying to create a render target that isn't in the default pool\n");
812 /* mark the texture as dirty so that it gets loaded first time around*/
813 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
814 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
815 This, Width, Height, Format, debug_d3dformat(Format),
816 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
818 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
819 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
820 This->ddraw_primary = (IWineD3DSurface *) object;
822 /* Look at the implementation and set the correct Vtable */
825 /* Nothing to do, it's set already */
829 object->lpVtbl = &IWineGDISurface_Vtbl;
833 /* To be sure to catch this */
834 ERR("Unknown requested surface implementation %d!\n", Impl);
835 IWineD3DSurface_Release((IWineD3DSurface *) object);
836 return WINED3DERR_INVALIDCALL;
839 /* Call the private setup routine */
840 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
844 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
845 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
846 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
847 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
850 IWineD3DTextureImpl *object;
855 unsigned int pow2Width;
856 unsigned int pow2Height;
859 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
860 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
861 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
863 /* TODO: It should only be possible to create textures for formats
864 that are reported as supported */
865 if (WINED3DFMT_UNKNOWN >= Format) {
866 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
867 return WINED3DERR_INVALIDCALL;
870 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
871 D3DINITIALIZEBASETEXTURE(object->baseTexture);
872 object->width = Width;
873 object->height = Height;
875 /** Non-power2 support **/
876 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
880 /* Find the nearest pow2 match */
881 pow2Width = pow2Height = 1;
882 while (pow2Width < Width) pow2Width <<= 1;
883 while (pow2Height < Height) pow2Height <<= 1;
886 /** FIXME: add support for real non-power-two if it's provided by the video card **/
887 /* Precalculated scaling for 'faked' non power of two texture coords */
888 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
889 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
890 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
892 /* Calculate levels for mip mapping */
894 TRACE("calculating levels %d\n", object->baseTexture.levels);
895 object->baseTexture.levels++;
898 while (tmpW > 1 || tmpH > 1) {
899 tmpW = max(1, tmpW >> 1);
900 tmpH = max(1, tmpH >> 1);
901 object->baseTexture.levels++;
903 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
906 /* Generate all the surfaces */
909 for (i = 0; i < object->baseTexture.levels; i++)
911 /* use the callback to create the texture surface */
912 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
913 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
914 FIXME("Failed to create surface %p\n", object);
916 object->surfaces[i] = NULL;
917 IWineD3DTexture_Release((IWineD3DTexture *)object);
923 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
924 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
925 /* calculate the next mipmap level */
926 tmpW = max(1, tmpW >> 1);
927 tmpH = max(1, tmpH >> 1);
930 TRACE("(%p) : Created texture %p\n", This, object);
934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
935 UINT Width, UINT Height, UINT Depth,
936 UINT Levels, DWORD Usage,
937 WINED3DFORMAT Format, WINED3DPOOL Pool,
938 IWineD3DVolumeTexture **ppVolumeTexture,
939 HANDLE *pSharedHandle, IUnknown *parent,
940 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
943 IWineD3DVolumeTextureImpl *object;
949 /* TODO: It should only be possible to create textures for formats
950 that are reported as supported */
951 if (WINED3DFMT_UNKNOWN >= Format) {
952 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
953 return WINED3DERR_INVALIDCALL;
956 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
957 D3DINITIALIZEBASETEXTURE(object->baseTexture);
959 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
960 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
962 object->width = Width;
963 object->height = Height;
964 object->depth = Depth;
966 /* Calculate levels for mip mapping */
968 object->baseTexture.levels++;
972 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
973 tmpW = max(1, tmpW >> 1);
974 tmpH = max(1, tmpH >> 1);
975 tmpD = max(1, tmpD >> 1);
976 object->baseTexture.levels++;
978 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
981 /* Generate all the surfaces */
986 for (i = 0; i < object->baseTexture.levels; i++)
989 /* Create the volume */
990 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
991 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
994 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
995 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
996 *ppVolumeTexture = NULL;
1000 /* Set its container to this object */
1001 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1003 /* calcualte the next mipmap level */
1004 tmpW = max(1, tmpW >> 1);
1005 tmpH = max(1, tmpH >> 1);
1006 tmpD = max(1, tmpD >> 1);
1009 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1010 TRACE("(%p) : Created volume texture %p\n", This, object);
1014 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1015 UINT Width, UINT Height, UINT Depth,
1017 WINED3DFORMAT Format, WINED3DPOOL Pool,
1018 IWineD3DVolume** ppVolume,
1019 HANDLE* pSharedHandle, IUnknown *parent) {
1021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1022 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1023 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1025 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1027 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1028 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1030 object->currentDesc.Width = Width;
1031 object->currentDesc.Height = Height;
1032 object->currentDesc.Depth = Depth;
1033 object->bytesPerPixel = formatDesc->bpp;
1035 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1036 object->lockable = TRUE;
1037 object->locked = FALSE;
1038 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1039 object->dirty = TRUE;
1041 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1044 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1045 UINT Levels, DWORD Usage,
1046 WINED3DFORMAT Format, WINED3DPOOL Pool,
1047 IWineD3DCubeTexture **ppCubeTexture,
1048 HANDLE *pSharedHandle, IUnknown *parent,
1049 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1052 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1056 unsigned int pow2EdgeLength = EdgeLength;
1058 /* TODO: It should only be possible to create textures for formats
1059 that are reported as supported */
1060 if (WINED3DFMT_UNKNOWN >= Format) {
1061 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1066 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1068 TRACE("(%p) Create Cube Texture\n", This);
1070 /** Non-power2 support **/
1072 /* Find the nearest pow2 match */
1074 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1076 object->edgeLength = EdgeLength;
1077 /* TODO: support for native non-power 2 */
1078 /* Precalculated scaling for 'faked' non power of two texture coords */
1079 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1081 /* Calculate levels for mip mapping */
1083 object->baseTexture.levels++;
1086 tmpW = max(1, tmpW >> 1);
1087 object->baseTexture.levels++;
1089 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1092 /* Generate all the surfaces */
1094 for (i = 0; i < object->baseTexture.levels; i++) {
1096 /* Create the 6 faces */
1097 for (j = 0; j < 6; j++) {
1099 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1100 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1102 if(hr!= WINED3D_OK) {
1106 for (l = 0; l < j; l++) {
1107 IWineD3DSurface_Release(object->surfaces[j][i]);
1109 for (k = 0; k < i; k++) {
1110 for (l = 0; l < 6; l++) {
1111 IWineD3DSurface_Release(object->surfaces[l][j]);
1115 FIXME("(%p) Failed to create surface\n",object);
1116 HeapFree(GetProcessHeap(),0,object);
1117 *ppCubeTexture = NULL;
1120 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1121 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1123 tmpW = max(1, tmpW >> 1);
1126 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1127 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1131 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1133 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1134 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1136 /* Just a check to see if we support this type of query */
1138 case WINED3DQUERYTYPE_OCCLUSION:
1139 TRACE("(%p) occlusion query\n", This);
1140 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1143 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1146 case WINED3DQUERYTYPE_EVENT:
1147 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1148 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1150 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1154 case WINED3DQUERYTYPE_VCACHE:
1155 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1156 case WINED3DQUERYTYPE_VERTEXSTATS:
1157 case WINED3DQUERYTYPE_TIMESTAMP:
1158 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1159 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1160 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1161 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1162 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1163 case WINED3DQUERYTYPE_PIXELTIMINGS:
1164 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1165 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1167 FIXME("(%p) Unhandled query type %d\n", This, Type);
1169 if(NULL == ppQuery || hr != WINED3D_OK) {
1173 D3DCREATEOBJECTINSTANCE(object, Query)
1174 object->type = Type;
1175 /* allocated the 'extended' data based on the type of query requested */
1177 case WINED3DQUERYTYPE_OCCLUSION:
1178 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1179 TRACE("(%p) Allocating data for an occlusion query\n", This);
1180 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1181 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1184 case WINED3DQUERYTYPE_VCACHE:
1185 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1186 case WINED3DQUERYTYPE_VERTEXSTATS:
1187 case WINED3DQUERYTYPE_EVENT:
1188 case WINED3DQUERYTYPE_TIMESTAMP:
1189 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1190 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1191 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1192 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1193 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1194 case WINED3DQUERYTYPE_PIXELTIMINGS:
1195 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1196 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1198 object->extendedData = 0;
1199 FIXME("(%p) Unhandled query type %d\n",This , Type);
1201 TRACE("(%p) : Created Query %p\n", This, object);
1205 /*****************************************************************************
1206 * IWineD3DDeviceImpl_SetupFullscreenWindow
1208 * Helper function that modifies a HWND's Style and ExStyle for proper
1212 * iface: Pointer to the IWineD3DDevice interface
1213 * window: Window to setup
1215 *****************************************************************************/
1216 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1219 LONG style, exStyle;
1220 /* Don't do anything if an original style is stored.
1221 * That shouldn't happen
1223 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1224 if (This->style || This->exStyle) {
1225 ERR("(%p): Want to change the window parameters of HWND %p, but "
1226 "another style is stored for restoration afterwards\n", This, window);
1229 /* Get the parameters and save them */
1230 style = GetWindowLongW(window, GWL_STYLE);
1231 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1232 This->style = style;
1233 This->exStyle = exStyle;
1235 /* Filter out window decorations */
1236 style &= ~WS_CAPTION;
1237 style &= ~WS_THICKFRAME;
1238 exStyle &= ~WS_EX_WINDOWEDGE;
1239 exStyle &= ~WS_EX_CLIENTEDGE;
1241 /* Make sure the window is managed, otherwise we won't get keyboard input */
1242 style |= WS_POPUP | WS_SYSMENU;
1244 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1245 This->style, This->exStyle, style, exStyle);
1247 SetWindowLongW(window, GWL_STYLE, style);
1248 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1250 /* Inform the window about the update. */
1251 SetWindowPos(window, HWND_TOP, 0, 0,
1252 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1253 ShowWindow(window, TRUE);
1256 /*****************************************************************************
1257 * IWineD3DDeviceImpl_RestoreWindow
1259 * Helper function that restores a windows' properties when taking it out
1260 * of fullscreen mode
1263 * iface: Pointer to the IWineD3DDevice interface
1264 * window: Window to setup
1266 *****************************************************************************/
1267 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1271 * switch, do nothing
1273 if (!This->style && !This->exStyle) return;
1275 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1276 This, window, This->style, This->exStyle);
1278 SetWindowLongW(window, GWL_STYLE, This->style);
1279 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1281 /* Delete the old values */
1285 /* Inform the window about the update */
1286 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1287 0, 0, 0, 0, /* Pos, Size, ignored */
1288 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1291 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1292 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1294 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1295 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1300 HRESULT hr = WINED3D_OK;
1301 IUnknown *bufferParent;
1304 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1306 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1307 * does a device hold a reference to a swap chain giving them a lifetime of the device
1308 * or does the swap chain notify the device of its destruction.
1309 *******************************/
1311 /* Check the params */
1312 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1313 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1314 return WINED3DERR_INVALIDCALL;
1315 } else if (pPresentationParameters->BackBufferCount > 1) {
1316 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");
1319 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1321 /*********************
1322 * Lookup the window Handle and the relating X window handle
1323 ********************/
1325 /* Setup hwnd we are using, plus which display this equates to */
1326 object->win_handle = pPresentationParameters->hDeviceWindow;
1327 if (!object->win_handle) {
1328 object->win_handle = This->createParms.hFocusWindow;
1331 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1332 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1333 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1334 return WINED3DERR_NOTAVAILABLE;
1336 hDc = GetDC(object->win_handle);
1337 display = get_display(hDc);
1338 ReleaseDC(object->win_handle, hDc);
1339 TRACE("Using a display of %p %p\n", display, hDc);
1341 if (NULL == display || NULL == hDc) {
1342 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1343 return WINED3DERR_NOTAVAILABLE;
1346 if (object->win == 0) {
1347 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1348 return WINED3DERR_NOTAVAILABLE;
1351 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1352 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1353 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1355 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1356 * then the corresponding dimension of the client area of the hDeviceWindow
1357 * (or the focus window, if hDeviceWindow is NULL) is taken.
1358 **********************/
1360 if (pPresentationParameters->Windowed &&
1361 ((pPresentationParameters->BackBufferWidth == 0) ||
1362 (pPresentationParameters->BackBufferHeight == 0))) {
1365 GetClientRect(object->win_handle, &Rect);
1367 if (pPresentationParameters->BackBufferWidth == 0) {
1368 pPresentationParameters->BackBufferWidth = Rect.right;
1369 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1371 if (pPresentationParameters->BackBufferHeight == 0) {
1372 pPresentationParameters->BackBufferHeight = Rect.bottom;
1373 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1377 /* Put the correct figures in the presentation parameters */
1378 TRACE("Copying across presentation parameters\n");
1379 object->presentParms = *pPresentationParameters;
1381 TRACE("calling rendertarget CB\n");
1382 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1384 object->presentParms.BackBufferWidth,
1385 object->presentParms.BackBufferHeight,
1386 object->presentParms.BackBufferFormat,
1387 object->presentParms.MultiSampleType,
1388 object->presentParms.MultiSampleQuality,
1389 TRUE /* Lockable */,
1390 &object->frontBuffer,
1391 NULL /* pShared (always null)*/);
1392 if (object->frontBuffer != NULL) {
1393 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1395 ERR("Failed to create the front buffer\n");
1400 * Create an opengl context for the display visual
1401 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1402 * use different properties after that point in time. FIXME: How to handle when requested format
1403 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1404 * it chooses is identical to the one already being used!
1405 **********************************/
1407 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1409 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1412 if (!object->context) {
1413 ERR("Failed to create a new context\n");
1414 hr = WINED3DERR_NOTAVAILABLE;
1417 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1418 object->win_handle, object->context->glCtx, object->win);
1421 /*********************
1422 * Windowed / Fullscreen
1423 *******************/
1426 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1427 * so we should really check to see if there is a fullscreen swapchain already
1428 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1429 **************************************/
1431 if (!pPresentationParameters->Windowed) {
1438 /* Get info on the current display setup */
1440 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1443 /* Change the display settings */
1444 memset(&devmode, 0, sizeof(DEVMODEW));
1445 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1446 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1447 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1448 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1449 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1450 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1452 /* For GetDisplayMode */
1453 This->ddraw_width = devmode.dmPelsWidth;
1454 This->ddraw_height = devmode.dmPelsHeight;
1455 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1457 IWineD3DDevice_SetFullscreen(iface, TRUE);
1459 /* And finally clip mouse to our screen */
1460 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1461 ClipCursor(&clip_rc);
1464 /*********************
1465 * Create the back, front and stencil buffers
1466 *******************/
1467 if(object->presentParms.BackBufferCount > 0) {
1470 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1471 if(!object->backBuffer) {
1472 ERR("Out of memory\n");
1477 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1478 TRACE("calling rendertarget CB\n");
1479 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1481 object->presentParms.BackBufferWidth,
1482 object->presentParms.BackBufferHeight,
1483 object->presentParms.BackBufferFormat,
1484 object->presentParms.MultiSampleType,
1485 object->presentParms.MultiSampleQuality,
1486 TRUE /* Lockable */,
1487 &object->backBuffer[i],
1488 NULL /* pShared (always null)*/);
1489 if(hr == WINED3D_OK && object->backBuffer[i]) {
1490 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1492 ERR("Cannot create new back buffer\n");
1496 glDrawBuffer(GL_BACK);
1497 checkGLcall("glDrawBuffer(GL_BACK)");
1501 object->backBuffer = NULL;
1503 /* Single buffering - draw to front buffer */
1505 glDrawBuffer(GL_FRONT);
1506 checkGLcall("glDrawBuffer(GL_FRONT)");
1510 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1511 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1512 TRACE("Creating depth stencil buffer\n");
1513 if (This->depthStencilBuffer == NULL ) {
1514 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1516 object->presentParms.BackBufferWidth,
1517 object->presentParms.BackBufferHeight,
1518 object->presentParms.AutoDepthStencilFormat,
1519 object->presentParms.MultiSampleType,
1520 object->presentParms.MultiSampleQuality,
1521 FALSE /* FIXME: Discard */,
1522 &This->depthStencilBuffer,
1523 NULL /* pShared (always null)*/ );
1524 if (This->depthStencilBuffer != NULL)
1525 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1528 /** TODO: A check on width, height and multisample types
1529 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1530 ****************************/
1531 object->wantsDepthStencilBuffer = TRUE;
1533 object->wantsDepthStencilBuffer = FALSE;
1536 TRACE("Created swapchain %p\n", object);
1537 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1541 if (object->backBuffer) {
1543 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1544 if(object->backBuffer[i]) {
1545 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1546 IUnknown_Release(bufferParent); /* once for the get parent */
1547 if (IUnknown_Release(bufferParent) > 0) {
1548 FIXME("(%p) Something's still holding the back buffer\n",This);
1552 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1553 object->backBuffer = NULL;
1555 if(object->context) {
1556 DestroyContext(This, object->context);
1558 if(object->frontBuffer) {
1559 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1560 IUnknown_Release(bufferParent); /* once for the get parent */
1561 if (IUnknown_Release(bufferParent) > 0) {
1562 FIXME("(%p) Something's still holding the front buffer\n",This);
1565 if(object) HeapFree(GetProcessHeap(), 0, object);
1569 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1570 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1572 TRACE("(%p)\n", This);
1574 return This->NumberOfSwapChains;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1579 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1581 if(iSwapChain < This->NumberOfSwapChains) {
1582 *pSwapChain = This->swapchains[iSwapChain];
1583 IWineD3DSwapChain_AddRef(*pSwapChain);
1584 TRACE("(%p) returning %p\n", This, *pSwapChain);
1587 TRACE("Swapchain out of range\n");
1589 return WINED3DERR_INVALIDCALL;
1594 * Vertex Declaration
1596 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1597 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1599 IWineD3DVertexDeclarationImpl *object = NULL;
1600 HRESULT hr = WINED3D_OK;
1602 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1603 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1605 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1608 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1613 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1614 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1616 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1617 HRESULT hr = WINED3D_OK;
1618 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1619 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1621 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1623 if (vertex_declaration) {
1624 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1627 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1629 if (WINED3D_OK != hr) {
1630 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1631 IWineD3DVertexShader_Release(*ppVertexShader);
1632 return WINED3DERR_INVALIDCALL;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1641 HRESULT hr = WINED3D_OK;
1643 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1644 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1645 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1646 if (WINED3D_OK == hr) {
1647 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1649 WARN("(%p) : Failed to create pixel shader\n", This);
1655 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1657 IWineD3DPaletteImpl *object;
1659 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1661 /* Create the new object */
1662 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1664 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1665 return E_OUTOFMEMORY;
1668 object->lpVtbl = &IWineD3DPalette_Vtbl;
1670 object->Flags = Flags;
1671 object->parent = Parent;
1672 object->wineD3DDevice = This;
1673 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1675 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1678 HeapFree( GetProcessHeap(), 0, object);
1679 return E_OUTOFMEMORY;
1682 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1684 IWineD3DPalette_Release((IWineD3DPalette *) object);
1688 *Palette = (IWineD3DPalette *) object;
1693 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1695 IWineD3DSwapChainImpl *swapchain;
1698 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1699 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1701 /* TODO: Test if OpenGL is compiled in and loaded */
1703 /* Initialize the texture unit mapping to a 1:1 mapping */
1704 for(state = 0; state < MAX_SAMPLERS; state++) {
1705 This->texUnitMap[state] = state;
1707 This->oneToOneTexUnitMap = TRUE;
1709 /* Setup the implicit swapchain */
1710 TRACE("Creating implicit swapchain\n");
1711 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1712 WARN("Failed to create implicit swapchain\n");
1713 return WINED3DERR_INVALIDCALL;
1716 This->NumberOfSwapChains = 1;
1717 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1718 if(!This->swapchains) {
1719 ERR("Out of memory!\n");
1720 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1721 return E_OUTOFMEMORY;
1723 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1725 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1727 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1728 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1729 This->render_targets[0] = swapchain->backBuffer[0];
1730 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1733 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1734 This->render_targets[0] = swapchain->frontBuffer;
1735 This->lastActiveRenderTarget = swapchain->frontBuffer;
1737 IWineD3DSurface_AddRef(This->render_targets[0]);
1738 This->activeContext = swapchain->context;
1740 /* Depth Stencil support */
1741 This->stencilBufferTarget = This->depthStencilBuffer;
1742 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1743 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1745 if (NULL != This->stencilBufferTarget) {
1746 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1749 /* Set up some starting GL setup */
1752 * Initialize openGL extension related variables
1753 * with Default values
1756 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1757 /* Setup all the devices defaults */
1758 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1760 IWineD3DImpl_CheckGraphicsMemory();
1763 /* Initialize our list of GLSL programs */
1764 list_init(&This->glsl_shader_progs);
1766 { /* Set a default viewport */
1770 vp.Width = pPresentationParameters->BackBufferWidth;
1771 vp.Height = pPresentationParameters->BackBufferHeight;
1774 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1777 /* Initialize the current view state */
1778 This->view_ident = 1;
1779 This->contexts[0]->last_was_rhw = 0;
1780 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1781 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1782 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1785 /* Clear the screen */
1786 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1788 This->d3d_initialized = TRUE;
1792 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1796 TRACE("(%p)\n", This);
1798 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1800 /* Delete the pbuffer context if there is any */
1801 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1803 /* Delete the mouse cursor texture */
1804 if(This->cursorTexture) {
1806 glDeleteTextures(1, &This->cursorTexture);
1808 This->cursorTexture = 0;
1811 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1812 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1815 /* Release the buffers (with sanity checks)*/
1816 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1817 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1818 if(This->depthStencilBuffer != This->stencilBufferTarget)
1819 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1821 This->stencilBufferTarget = NULL;
1823 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1824 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1825 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1827 TRACE("Setting rendertarget to NULL\n");
1828 This->render_targets[0] = NULL;
1830 if (This->depthStencilBuffer) {
1831 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1832 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1834 This->depthStencilBuffer = NULL;
1837 for(i=0; i < This->NumberOfSwapChains; i++) {
1838 TRACE("Releasing the implicit swapchain %d\n", i);
1839 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1840 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1844 HeapFree(GetProcessHeap(), 0, This->swapchains);
1845 This->swapchains = NULL;
1846 This->NumberOfSwapChains = 0;
1848 This->d3d_initialized = FALSE;
1852 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1854 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1856 /* Setup the window for fullscreen mode */
1857 if(fullscreen && !This->ddraw_fullscreen) {
1858 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1859 } else if(!fullscreen && This->ddraw_fullscreen) {
1860 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1863 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1864 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1865 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1868 This->ddraw_fullscreen = fullscreen;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1875 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1878 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1880 /* Resize the screen even without a window:
1881 * The app could have unset it with SetCooperativeLevel, but not called
1882 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1883 * but we don't have any hwnd
1886 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1887 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1888 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1889 devmode.dmPelsWidth = pMode->Width;
1890 devmode.dmPelsHeight = pMode->Height;
1892 devmode.dmDisplayFrequency = pMode->RefreshRate;
1893 if (pMode->RefreshRate != 0) {
1894 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1897 /* Only change the mode if necessary */
1898 if( (This->ddraw_width == pMode->Width) &&
1899 (This->ddraw_height == pMode->Height) &&
1900 (This->ddraw_format == pMode->Format) &&
1901 (pMode->RefreshRate == 0) ) {
1905 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1906 if (ret != DISP_CHANGE_SUCCESSFUL) {
1907 if(devmode.dmDisplayFrequency != 0) {
1908 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1909 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1910 devmode.dmDisplayFrequency = 0;
1911 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1913 if(ret != DISP_CHANGE_SUCCESSFUL) {
1914 return DDERR_INVALIDMODE;
1918 /* Store the new values */
1919 This->ddraw_width = pMode->Width;
1920 This->ddraw_height = pMode->Height;
1921 This->ddraw_format = pMode->Format;
1923 /* Only do this with a window of course */
1924 if(This->ddraw_window)
1925 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1927 /* And finally clip mouse to our screen */
1928 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1929 ClipCursor(&clip_rc);
1934 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1936 *ppD3D= This->wineD3D;
1937 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1938 IWineD3D_AddRef(*ppD3D);
1942 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1943 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1944 * into the video ram as possible and seeing how many fit
1945 * you can also get the correct initial value from nvidia and ATI's driver via X
1946 * texture memory is video memory + AGP memory
1947 *******************/
1948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1949 static BOOL showfixmes = TRUE;
1951 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1952 (wined3d_settings.emulated_textureram/(1024*1024)),
1953 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1956 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1957 (wined3d_settings.emulated_textureram/(1024*1024)),
1958 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1959 /* return simulated texture memory left */
1960 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1968 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1971 /* Update the current state block */
1972 This->updateStateBlock->changed.fvf = TRUE;
1973 This->updateStateBlock->set.fvf = TRUE;
1975 if(This->updateStateBlock->fvf == fvf) {
1976 TRACE("Application is setting the old fvf over, nothing to do\n");
1980 This->updateStateBlock->fvf = fvf;
1981 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1987 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1989 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1990 *pfvf = This->stateBlock->fvf;
1995 * Get / Set Stream Source
1997 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1999 IWineD3DVertexBuffer *oldSrc;
2001 if (StreamNumber >= MAX_STREAMS) {
2002 WARN("Stream out of range %d\n", StreamNumber);
2003 return WINED3DERR_INVALIDCALL;
2006 oldSrc = This->stateBlock->streamSource[StreamNumber];
2007 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2009 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2010 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2012 if(oldSrc == pStreamData &&
2013 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2014 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2015 TRACE("Application is setting the old values over, nothing to do\n");
2019 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2021 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2022 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2025 /* Handle recording of state blocks */
2026 if (This->isRecordingState) {
2027 TRACE("Recording... not performing anything\n");
2031 /* Need to do a getParent and pass the reffs up */
2032 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2033 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2034 so for now, just count internally */
2035 if (pStreamData != NULL) {
2036 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2037 InterlockedIncrement(&vbImpl->bindCount);
2039 if (oldSrc != NULL) {
2040 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2048 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2051 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2052 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2054 if (StreamNumber >= MAX_STREAMS) {
2055 WARN("Stream out of range %d\n", StreamNumber);
2056 return WINED3DERR_INVALIDCALL;
2058 *pStream = This->stateBlock->streamSource[StreamNumber];
2059 *pStride = This->stateBlock->streamStride[StreamNumber];
2061 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2064 if (*pStream != NULL) {
2065 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2070 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2072 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2073 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2075 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2076 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2078 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2079 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2080 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2082 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2083 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2090 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2094 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2096 TRACE("(%p) : returning %d\n", This, *Divider);
2102 * Get / Set & Multiply Transform
2104 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2107 /* Most of this routine, comments included copied from ddraw tree initially: */
2108 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2110 /* Handle recording of state blocks */
2111 if (This->isRecordingState) {
2112 TRACE("Recording... not performing anything\n");
2113 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2114 This->updateStateBlock->set.transform[d3dts] = TRUE;
2115 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2120 * If the new matrix is the same as the current one,
2121 * we cut off any further processing. this seems to be a reasonable
2122 * optimization because as was noticed, some apps (warcraft3 for example)
2123 * tend towards setting the same matrix repeatedly for some reason.
2125 * From here on we assume that the new matrix is different, wherever it matters.
2127 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2128 TRACE("The app is setting the same matrix over again\n");
2131 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2135 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2136 where ViewMat = Camera space, WorldMat = world space.
2138 In OpenGL, camera and world space is combined into GL_MODELVIEW
2139 matrix. The Projection matrix stay projection matrix.
2142 /* Capture the times we can just ignore the change for now */
2143 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2144 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2145 /* Handled by the state manager */
2148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2152 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2155 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2159 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2160 WINED3DMATRIX *mat = NULL;
2163 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2164 * below means it will be recorded in a state block change, but it
2165 * works regardless where it is recorded.
2166 * If this is found to be wrong, change to StateBlock.
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2171 if (State < HIGHEST_TRANSFORMSTATE)
2173 mat = &This->updateStateBlock->transforms[State];
2175 FIXME("Unhandled transform state!!\n");
2178 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2180 /* Apply change via set transform - will reapply to eg. lights this way */
2181 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2187 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2188 you can reference any indexes you want as long as that number max are enabled at any
2189 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2190 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2191 but when recording, just build a chain pretty much of commands to be replayed. */
2193 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2195 PLIGHTINFOEL *object = NULL;
2196 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2200 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2202 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2206 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2207 return WINED3DERR_INVALIDCALL;
2210 switch(pLight->Type) {
2211 case WINED3DLIGHT_POINT:
2212 case WINED3DLIGHT_SPOT:
2213 case WINED3DLIGHT_PARALLELPOINT:
2214 case WINED3DLIGHT_GLSPOT:
2215 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2218 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2219 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2220 return WINED3DERR_INVALIDCALL;
2224 case WINED3DLIGHT_DIRECTIONAL:
2225 /* Ignores attenuation */
2229 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2230 return WINED3DERR_INVALIDCALL;
2233 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2234 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2235 if(object->OriginalIndex == Index) break;
2240 TRACE("Adding new light\n");
2241 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2243 ERR("Out of memory error when allocating a light\n");
2244 return E_OUTOFMEMORY;
2246 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2247 object->glIndex = -1;
2248 object->OriginalIndex = Index;
2249 object->changed = TRUE;
2252 /* Initialize the object */
2253 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,
2254 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2255 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2256 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2257 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2258 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2259 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2261 /* Save away the information */
2262 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2264 switch (pLight->Type) {
2265 case WINED3DLIGHT_POINT:
2267 object->lightPosn[0] = pLight->Position.x;
2268 object->lightPosn[1] = pLight->Position.y;
2269 object->lightPosn[2] = pLight->Position.z;
2270 object->lightPosn[3] = 1.0f;
2271 object->cutoff = 180.0f;
2275 case WINED3DLIGHT_DIRECTIONAL:
2277 object->lightPosn[0] = -pLight->Direction.x;
2278 object->lightPosn[1] = -pLight->Direction.y;
2279 object->lightPosn[2] = -pLight->Direction.z;
2280 object->lightPosn[3] = 0.0;
2281 object->exponent = 0.0f;
2282 object->cutoff = 180.0f;
2285 case WINED3DLIGHT_SPOT:
2287 object->lightPosn[0] = pLight->Position.x;
2288 object->lightPosn[1] = pLight->Position.y;
2289 object->lightPosn[2] = pLight->Position.z;
2290 object->lightPosn[3] = 1.0;
2293 object->lightDirn[0] = pLight->Direction.x;
2294 object->lightDirn[1] = pLight->Direction.y;
2295 object->lightDirn[2] = pLight->Direction.z;
2296 object->lightDirn[3] = 1.0;
2299 * opengl-ish and d3d-ish spot lights use too different models for the
2300 * light "intensity" as a function of the angle towards the main light direction,
2301 * so we only can approximate very roughly.
2302 * however spot lights are rather rarely used in games (if ever used at all).
2303 * furthermore if still used, probably nobody pays attention to such details.
2305 if (pLight->Falloff == 0) {
2308 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2310 if (rho < 0.0001) rho = 0.0001f;
2311 object->exponent = -0.3/log(cos(rho/2));
2312 if (object->exponent > 128.0) {
2313 object->exponent = 128.0;
2315 object->cutoff = pLight->Phi*90/M_PI;
2321 FIXME("Unrecognized light type %d\n", pLight->Type);
2324 /* Update the live definitions if the light is currently assigned a glIndex */
2325 if (object->glIndex != -1 && !This->isRecordingState) {
2326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2332 PLIGHTINFOEL *lightInfo = NULL;
2333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2336 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2338 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2339 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2340 if(lightInfo->OriginalIndex == Index) break;
2344 if (lightInfo == NULL) {
2345 TRACE("Light information requested but light not defined\n");
2346 return WINED3DERR_INVALIDCALL;
2349 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2354 * Get / Set Light Enable
2355 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2358 PLIGHTINFOEL *lightInfo = NULL;
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2362 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2364 /* Tests show true = 128...not clear why */
2365 Enable = Enable? 128: 0;
2367 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2368 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2369 if(lightInfo->OriginalIndex == Index) break;
2372 TRACE("Found light: %p\n", lightInfo);
2374 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2375 if (lightInfo == NULL) {
2377 TRACE("Light enabled requested but light not defined, so defining one!\n");
2378 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2380 /* Search for it again! Should be fairly quick as near head of list */
2381 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2382 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2383 if(lightInfo->OriginalIndex == Index) break;
2386 if (lightInfo == NULL) {
2387 FIXME("Adding default lights has failed dismally\n");
2388 return WINED3DERR_INVALIDCALL;
2392 lightInfo->enabledChanged = TRUE;
2394 if(lightInfo->glIndex != -1) {
2395 if(!This->isRecordingState) {
2396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2399 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2400 lightInfo->glIndex = -1;
2402 TRACE("Light already disabled, nothing to do\n");
2405 if (lightInfo->glIndex != -1) {
2407 TRACE("Nothing to do as light was enabled\n");
2410 /* Find a free gl light */
2411 for(i = 0; i < This->maxConcurrentLights; i++) {
2412 if(This->stateBlock->activeLights[i] == NULL) {
2413 This->stateBlock->activeLights[i] = lightInfo;
2414 lightInfo->glIndex = i;
2418 if(lightInfo->glIndex == -1) {
2419 ERR("Too many concurrently active lights\n");
2420 return WINED3DERR_INVALIDCALL;
2423 /* i == lightInfo->glIndex */
2424 if(!This->isRecordingState) {
2425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2433 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2435 PLIGHTINFOEL *lightInfo = NULL;
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2439 TRACE("(%p) : for idx(%d)\n", This, Index);
2441 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2442 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2443 if(lightInfo->OriginalIndex == Index) break;
2447 if (lightInfo == NULL) {
2448 TRACE("Light enabled state requested but light not defined\n");
2449 return WINED3DERR_INVALIDCALL;
2451 /* true is 128 according to SetLightEnable */
2452 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2457 * Get / Set Clip Planes
2459 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2463 /* Validate Index */
2464 if (Index >= GL_LIMITS(clipplanes)) {
2465 TRACE("Application has requested clipplane this device doesn't support\n");
2466 return WINED3DERR_INVALIDCALL;
2469 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2470 This->updateStateBlock->set.clipplane[Index] = TRUE;
2471 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2472 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2473 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2474 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2476 /* Handle recording of state blocks */
2477 if (This->isRecordingState) {
2478 TRACE("Recording... not performing anything\n");
2486 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2487 glMatrixMode(GL_MODELVIEW);
2489 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2491 TRACE("Clipplane [%f,%f,%f,%f]\n",
2492 This->updateStateBlock->clipplane[Index][0],
2493 This->updateStateBlock->clipplane[Index][1],
2494 This->updateStateBlock->clipplane[Index][2],
2495 This->updateStateBlock->clipplane[Index][3]);
2496 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2497 checkGLcall("glClipPlane");
2505 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2507 TRACE("(%p) : for idx %d\n", This, Index);
2509 /* Validate Index */
2510 if (Index >= GL_LIMITS(clipplanes)) {
2511 TRACE("Application has requested clipplane this device doesn't support\n");
2512 return WINED3DERR_INVALIDCALL;
2515 pPlane[0] = This->stateBlock->clipplane[Index][0];
2516 pPlane[1] = This->stateBlock->clipplane[Index][1];
2517 pPlane[2] = This->stateBlock->clipplane[Index][2];
2518 pPlane[3] = This->stateBlock->clipplane[Index][3];
2523 * Get / Set Clip Plane Status
2524 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2526 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 FIXME("(%p) : stub\n", This);
2529 if (NULL == pClipStatus) {
2530 return WINED3DERR_INVALIDCALL;
2532 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2533 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2537 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 FIXME("(%p) : stub\n", This);
2540 if (NULL == pClipStatus) {
2541 return WINED3DERR_INVALIDCALL;
2543 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2544 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2549 * Get / Set Material
2551 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 This->updateStateBlock->changed.material = TRUE;
2555 This->updateStateBlock->set.material = TRUE;
2556 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2558 /* Handle recording of state blocks */
2559 if (This->isRecordingState) {
2560 TRACE("Recording... not performing anything\n");
2565 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2566 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2567 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2568 pMaterial->Ambient.b, pMaterial->Ambient.a);
2569 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2570 pMaterial->Specular.b, pMaterial->Specular.a);
2571 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2572 pMaterial->Emissive.b, pMaterial->Emissive.a);
2573 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2575 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2576 checkGLcall("glMaterialfv(GL_AMBIENT)");
2577 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2578 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2580 /* Only change material color if specular is enabled, otherwise it is set to black */
2581 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2582 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2583 checkGLcall("glMaterialfv(GL_SPECULAR");
2585 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2586 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2587 checkGLcall("glMaterialfv(GL_SPECULAR");
2589 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2590 checkGLcall("glMaterialfv(GL_EMISSION)");
2591 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2592 checkGLcall("glMaterialf(GL_SHININESS");
2598 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2601 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2602 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2603 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2604 pMaterial->Ambient.b, pMaterial->Ambient.a);
2605 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2606 pMaterial->Specular.b, pMaterial->Specular.a);
2607 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2608 pMaterial->Emissive.b, pMaterial->Emissive.a);
2609 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2617 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2618 UINT BaseVertexIndex) {
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2620 IWineD3DIndexBuffer *oldIdxs;
2621 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2623 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2624 oldIdxs = This->updateStateBlock->pIndexData;
2626 This->updateStateBlock->changed.indices = TRUE;
2627 This->updateStateBlock->set.indices = TRUE;
2628 This->updateStateBlock->pIndexData = pIndexData;
2629 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2631 /* Handle recording of state blocks */
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2637 /* The base vertex index affects the stream sources, while
2638 * The index buffer is a seperate index buffer state
2640 if(BaseVertexIndex != oldBaseIndex) {
2641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2643 if(oldIdxs != pIndexData) {
2644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 *ppIndexData = This->stateBlock->pIndexData;
2654 /* up ref count on ppindexdata */
2656 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2657 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2658 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2660 TRACE("(%p) No index data set\n", This);
2662 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2667 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 TRACE("(%p)->(%d)\n", This, BaseIndex);
2672 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2673 TRACE("Application is setting the old value over, nothing to do\n");
2677 This->updateStateBlock->baseVertexIndex = BaseIndex;
2679 if (This->isRecordingState) {
2680 TRACE("Recording... not performing anything\n");
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2688 * Get / Set Viewports
2690 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 TRACE("(%p)\n", This);
2694 This->updateStateBlock->changed.viewport = TRUE;
2695 This->updateStateBlock->set.viewport = TRUE;
2696 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2698 /* Handle recording of state blocks */
2699 if (This->isRecordingState) {
2700 TRACE("Recording... not performing anything\n");
2704 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2705 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2712 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 TRACE("(%p)\n", This);
2715 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2720 * Get / Set Render States
2721 * TODO: Verify against dx9 definitions
2723 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 DWORD oldValue = This->stateBlock->renderState[State];
2728 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2730 This->updateStateBlock->changed.renderState[State] = TRUE;
2731 This->updateStateBlock->set.renderState[State] = TRUE;
2732 This->updateStateBlock->renderState[State] = Value;
2734 /* Handle recording of state blocks */
2735 if (This->isRecordingState) {
2736 TRACE("Recording... not performing anything\n");
2740 /* Compared here and not before the assignment to allow proper stateblock recording */
2741 if(Value == oldValue) {
2742 TRACE("Application is setting the old value over, nothing to do\n");
2744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2750 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2753 *pValue = This->stateBlock->renderState[State];
2758 * Get / Set Sampler States
2759 * TODO: Verify against dx9 definitions
2762 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2767 * SetSampler is designed to allow for more than the standard up to 8 textures
2768 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2769 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2771 * http://developer.nvidia.com/object/General_FAQ.html#t6
2773 * There are two new settings for GForce
2775 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2776 * and the texture one:
2777 * GL_MAX_TEXTURE_COORDS_ARB.
2778 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2781 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2782 debug_d3dsamplerstate(Type), Type, Value);
2783 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2784 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2785 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2787 /* Handle recording of state blocks */
2788 if (This->isRecordingState) {
2789 TRACE("Recording... not performing anything\n");
2793 if(oldValue == Value) {
2794 TRACE("Application is setting the old value over, nothing to do\n");
2798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2803 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 *Value = This->stateBlock->samplerState[Sampler][Type];
2806 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 This->updateStateBlock->set.scissorRect = TRUE;
2815 This->updateStateBlock->changed.scissorRect = TRUE;
2816 if(memcmp(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect)) == 0) {
2817 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2820 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2822 if(This->isRecordingState) {
2823 TRACE("Recording... not performing anything\n");
2827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2832 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2836 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2840 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2842 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2844 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2846 This->updateStateBlock->vertexDecl = pDecl;
2847 This->updateStateBlock->changed.vertexDecl = TRUE;
2848 This->updateStateBlock->set.vertexDecl = TRUE;
2850 if (This->isRecordingState) {
2851 TRACE("Recording... not performing anything\n");
2853 } else if(pDecl == oldDecl) {
2854 /* Checked after the assignment to allow proper stateblock recording */
2855 TRACE("Application is setting the old declaration over, nothing to do\n");
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2863 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2868 *ppDecl = This->stateBlock->vertexDecl;
2869 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2873 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2877 This->updateStateBlock->vertexShader = pShader;
2878 This->updateStateBlock->changed.vertexShader = TRUE;
2879 This->updateStateBlock->set.vertexShader = TRUE;
2881 if (This->isRecordingState) {
2882 TRACE("Recording... not performing anything\n");
2884 } else if(oldShader == pShader) {
2885 /* Checked here to allow proper stateblock recording */
2886 TRACE("App is setting the old shader over, nothing to do\n");
2890 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2892 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2897 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 if (NULL == ppShader) {
2901 return WINED3DERR_INVALIDCALL;
2903 *ppShader = This->stateBlock->vertexShader;
2904 if( NULL != *ppShader)
2905 IWineD3DVertexShader_AddRef(*ppShader);
2907 TRACE("(%p) : returning %p\n", This, *ppShader);
2911 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2912 IWineD3DDevice *iface,
2914 CONST BOOL *srcData,
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 int i, cnt = min(count, MAX_CONST_B - start);
2920 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2921 iface, srcData, start, count);
2923 if (srcData == NULL || cnt < 0)
2924 return WINED3DERR_INVALIDCALL;
2926 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2927 for (i = 0; i < cnt; i++)
2928 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2930 for (i = start; i < cnt + start; ++i) {
2931 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2932 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2941 IWineD3DDevice *iface,
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 int cnt = min(count, MAX_CONST_B - start);
2949 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2950 iface, dstData, start, count);
2952 if (dstData == NULL || cnt < 0)
2953 return WINED3DERR_INVALIDCALL;
2955 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2959 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2960 IWineD3DDevice *iface,
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 int i, cnt = min(count, MAX_CONST_I - start);
2968 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2969 iface, srcData, start, count);
2971 if (srcData == NULL || cnt < 0)
2972 return WINED3DERR_INVALIDCALL;
2974 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2975 for (i = 0; i < cnt; i++)
2976 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2977 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2979 for (i = start; i < cnt + start; ++i) {
2980 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2981 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2989 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2990 IWineD3DDevice *iface,
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 int cnt = min(count, MAX_CONST_I - start);
2998 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2999 iface, dstData, start, count);
3001 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3002 return WINED3DERR_INVALIDCALL;
3004 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3009 IWineD3DDevice *iface,
3011 CONST float *srcData,
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3017 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3018 iface, srcData, start, count);
3020 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3021 return WINED3DERR_INVALIDCALL;
3023 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3024 for (i = 0; i < cnt; i++)
3025 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3026 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3028 for (i = start; i < cnt + start; ++i) {
3029 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3030 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3032 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3033 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3035 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3043 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3044 IWineD3DDevice *iface,
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3052 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3053 iface, dstData, start, count);
3055 if (dstData == NULL || cnt < 0)
3056 return WINED3DERR_INVALIDCALL;
3058 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3062 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3064 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3069 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3071 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3072 * it is never called.
3075 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3076 * that would be really messy and require shader recompilation
3077 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3078 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3079 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3080 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3082 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3083 if(This->oneToOneTexUnitMap) {
3084 TRACE("Not touching 1:1 map\n");
3087 TRACE("Restoring 1:1 texture unit mapping\n");
3088 /* Restore a 1:1 mapping */
3089 for(i = 0; i < MAX_SAMPLERS; i++) {
3090 if(This->texUnitMap[i] != i) {
3091 This->texUnitMap[i] = i;
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3093 markTextureStagesDirty(This, i);
3096 This->oneToOneTexUnitMap = TRUE;
3099 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3100 * First, see if we can succeed at all
3103 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3104 if(This->stateBlock->textures[i] == NULL) tex++;
3107 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3108 FIXME("Too many bound textures to support the combiner settings\n");
3112 /* Now work out the mapping */
3114 This->oneToOneTexUnitMap = FALSE;
3115 WARN("Non 1:1 mapping UNTESTED!\n");
3116 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3117 /* Skip NULL textures */
3118 if (!This->stateBlock->textures[i]) {
3119 /* Map to -1, so the check below doesn't fail if a non-NULL
3120 * texture is set on this stage */
3121 TRACE("Mapping texture stage %d to -1\n", i);
3122 This->texUnitMap[i] = -1;
3127 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3128 if(This->texUnitMap[i] != tex) {
3129 This->texUnitMap[i] = tex;
3130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3131 markTextureStagesDirty(This, i);
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3142 This->updateStateBlock->pixelShader = pShader;
3143 This->updateStateBlock->changed.pixelShader = TRUE;
3144 This->updateStateBlock->set.pixelShader = TRUE;
3146 /* Handle recording of state blocks */
3147 if (This->isRecordingState) {
3148 TRACE("Recording... not performing anything\n");
3151 if (This->isRecordingState) {
3152 TRACE("Recording... not performing anything\n");
3156 if(pShader == oldShader) {
3157 TRACE("App is setting the old pixel shader over, nothing to do\n");
3161 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3164 /* Rebuild the texture unit mapping if nvrc's are supported */
3165 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3166 IWineD3DDeviceImpl_FindTexUnitMap(This);
3172 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3175 if (NULL == ppShader) {
3176 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3177 return WINED3DERR_INVALIDCALL;
3180 *ppShader = This->stateBlock->pixelShader;
3181 if (NULL != *ppShader) {
3182 IWineD3DPixelShader_AddRef(*ppShader);
3184 TRACE("(%p) : returning %p\n", This, *ppShader);
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3189 IWineD3DDevice *iface,
3191 CONST BOOL *srcData,
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 int i, cnt = min(count, MAX_CONST_B - start);
3197 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3198 iface, srcData, start, count);
3200 if (srcData == NULL || cnt < 0)
3201 return WINED3DERR_INVALIDCALL;
3203 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3204 for (i = 0; i < cnt; i++)
3205 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3207 for (i = start; i < cnt + start; ++i) {
3208 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3209 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3217 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3218 IWineD3DDevice *iface,
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 int cnt = min(count, MAX_CONST_B - start);
3226 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3227 iface, dstData, start, count);
3229 if (dstData == NULL || cnt < 0)
3230 return WINED3DERR_INVALIDCALL;
3232 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3236 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3237 IWineD3DDevice *iface,
3242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3243 int i, cnt = min(count, MAX_CONST_I - start);
3245 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3246 iface, srcData, start, count);
3248 if (srcData == NULL || cnt < 0)
3249 return WINED3DERR_INVALIDCALL;
3251 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3252 for (i = 0; i < cnt; i++)
3253 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3254 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3256 for (i = start; i < cnt + start; ++i) {
3257 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3258 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3266 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3267 IWineD3DDevice *iface,
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 int cnt = min(count, MAX_CONST_I - start);
3275 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3276 iface, dstData, start, count);
3278 if (dstData == NULL || cnt < 0)
3279 return WINED3DERR_INVALIDCALL;
3281 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3285 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3286 IWineD3DDevice *iface,
3288 CONST float *srcData,
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3294 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3295 iface, srcData, start, count);
3297 if (srcData == NULL || cnt < 0)
3298 return WINED3DERR_INVALIDCALL;
3300 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3301 for (i = 0; i < cnt; i++)
3302 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3303 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3305 for (i = start; i < cnt + start; ++i) {
3306 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3307 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3309 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3310 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3312 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3320 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3321 IWineD3DDevice *iface,
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3329 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3330 iface, dstData, start, count);
3332 if (dstData == NULL || cnt < 0)
3333 return WINED3DERR_INVALIDCALL;
3335 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3339 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3341 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3342 char *dest_ptr, *dest_conv = NULL;
3344 DWORD DestFVF = dest->fvf;
3346 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3350 if (SrcFVF & WINED3DFVF_NORMAL) {
3351 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3354 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3355 ERR("Source has no position mask\n");
3356 return WINED3DERR_INVALIDCALL;
3359 /* We might access VBOs from this code, so hold the lock */
3362 if (dest->resource.allocatedMemory == NULL) {
3363 /* This may happen if we do direct locking into a vbo. Unlikely,
3364 * but theoretically possible(ddraw processvertices test)
3366 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3367 if(!dest->resource.allocatedMemory) {
3369 ERR("Out of memory\n");
3370 return E_OUTOFMEMORY;
3374 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3375 checkGLcall("glBindBufferARB");
3376 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3378 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3380 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3381 checkGLcall("glUnmapBufferARB");
3385 /* Get a pointer into the destination vbo(create one if none exists) and
3386 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3388 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3393 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3394 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3396 ERR("glMapBuffer failed\n");
3397 /* Continue without storing converted vertices */
3402 * a) WINED3DRS_CLIPPING is enabled
3403 * b) WINED3DVOP_CLIP is passed
3405 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3406 static BOOL warned = FALSE;
3408 * The clipping code is not quite correct. Some things need
3409 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3410 * so disable clipping for now.
3411 * (The graphics in Half-Life are broken, and my processvertices
3412 * test crashes with IDirect3DDevice3)
3418 FIXME("Clipping is broken and disabled for now\n");
3420 } else doClip = FALSE;
3421 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3423 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3426 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3429 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3430 WINED3DTS_PROJECTION,
3432 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3433 WINED3DTS_WORLDMATRIX(0),
3436 TRACE("View mat:\n");
3437 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);
3438 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);
3439 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);
3440 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);
3442 TRACE("Proj mat:\n");
3443 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);
3444 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);
3445 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);
3446 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);
3448 TRACE("World mat:\n");
3449 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);
3450 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);
3451 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);
3452 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);
3454 /* Get the viewport */
3455 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3456 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3457 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3459 multiply_matrix(&mat,&view_mat,&world_mat);
3460 multiply_matrix(&mat,&proj_mat,&mat);
3462 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3464 for (i = 0; i < dwCount; i+= 1) {
3465 unsigned int tex_index;
3467 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3468 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3469 /* The position first */
3471 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3473 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3475 /* Multiplication with world, view and projection matrix */
3476 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);
3477 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);
3478 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);
3479 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);
3481 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3483 /* WARNING: The following things are taken from d3d7 and were not yet checked
3484 * against d3d8 or d3d9!
3487 /* Clipping conditions: From
3488 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3490 * A vertex is clipped if it does not match the following requirements
3494 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3496 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3497 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3502 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3503 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3506 /* "Normal" viewport transformation (not clipped)
3507 * 1) The values are divided by rhw
3508 * 2) The y axis is negative, so multiply it with -1
3509 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3510 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3511 * 4) Multiply x with Width/2 and add Width/2
3512 * 5) The same for the height
3513 * 6) Add the viewpoint X and Y to the 2D coordinates and
3514 * The minimum Z value to z
3515 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3517 * Well, basically it's simply a linear transformation into viewport
3529 z *= vp.MaxZ - vp.MinZ;
3531 x += vp.Width / 2 + vp.X;
3532 y += vp.Height / 2 + vp.Y;
3537 /* That vertex got clipped
3538 * Contrary to OpenGL it is not dropped completely, it just
3539 * undergoes a different calculation.
3541 TRACE("Vertex got clipped\n");
3548 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3549 * outside of the main vertex buffer memory. That needs some more
3554 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3557 ( (float *) dest_ptr)[0] = x;
3558 ( (float *) dest_ptr)[1] = y;
3559 ( (float *) dest_ptr)[2] = z;
3560 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3562 dest_ptr += 3 * sizeof(float);
3564 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3565 dest_ptr += sizeof(float);
3570 ( (float *) dest_conv)[0] = x * w;
3571 ( (float *) dest_conv)[1] = y * w;
3572 ( (float *) dest_conv)[2] = z * w;
3573 ( (float *) dest_conv)[3] = w;
3575 dest_conv += 3 * sizeof(float);
3577 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3578 dest_conv += sizeof(float);
3582 if (DestFVF & WINED3DFVF_PSIZE) {
3583 dest_ptr += sizeof(DWORD);
3584 if(dest_conv) dest_conv += sizeof(DWORD);
3586 if (DestFVF & WINED3DFVF_NORMAL) {
3588 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3589 /* AFAIK this should go into the lighting information */
3590 FIXME("Didn't expect the destination to have a normal\n");
3591 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3593 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3597 if (DestFVF & WINED3DFVF_DIFFUSE) {
3599 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3601 static BOOL warned = FALSE;
3604 ERR("No diffuse color in source, but destination has one\n");
3608 *( (DWORD *) dest_ptr) = 0xffffffff;
3609 dest_ptr += sizeof(DWORD);
3612 *( (DWORD *) dest_conv) = 0xffffffff;
3613 dest_conv += sizeof(DWORD);
3617 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3619 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3620 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3621 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3622 dest_conv += sizeof(DWORD);
3627 if (DestFVF & WINED3DFVF_SPECULAR) {
3628 /* What's the color value in the feedback buffer? */
3630 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3632 static BOOL warned = FALSE;
3635 ERR("No specular color in source, but destination has one\n");
3639 *( (DWORD *) dest_ptr) = 0xFF000000;
3640 dest_ptr += sizeof(DWORD);
3643 *( (DWORD *) dest_conv) = 0xFF000000;
3644 dest_conv += sizeof(DWORD);
3648 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3650 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3651 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3652 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3653 dest_conv += sizeof(DWORD);
3658 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3660 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3661 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3663 ERR("No source texture, but destination requests one\n");
3664 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3665 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3668 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3670 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3677 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3678 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3685 #undef copy_and_next
3687 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3689 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3690 WineDirect3DVertexStridedData strided;
3691 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3694 WARN("NULL source vertex buffer\n");
3695 return WINED3DERR_INVALIDCALL;
3697 /* We don't need the source vbo because this buffer is only used as
3698 * a source for ProcessVertices. Avoid wasting resources by converting the
3699 * buffer and loading the VBO
3702 TRACE("Releasing the source vbo, it won't be needed\n");
3704 if(!SrcImpl->resource.allocatedMemory) {
3705 /* Rescue the data from the buffer */
3707 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3708 if(!SrcImpl->resource.allocatedMemory) {
3709 ERR("Out of memory\n");
3710 return E_OUTOFMEMORY;
3714 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3715 checkGLcall("glBindBufferARB");
3717 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3719 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3722 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3723 checkGLcall("glUnmapBufferARB");
3728 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3729 checkGLcall("glBindBufferARB");
3730 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3731 checkGLcall("glDeleteBuffersARB");
3737 memset(&strided, 0, sizeof(strided));
3738 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3740 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3744 * Get / Set Texture Stage States
3745 * TODO: Verify against dx9 definitions
3747 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3749 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3751 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3753 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3755 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3756 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3757 This->updateStateBlock->textureState[Stage][Type] = Value;
3759 if (This->isRecordingState) {
3760 TRACE("Recording... not performing anything\n");
3764 /* Checked after the assignments to allow proper stateblock recording */
3765 if(oldValue == Value) {
3766 TRACE("App is setting the old value over, nothing to do\n");
3770 if(Stage > This->stateBlock->lowest_disabled_stage &&
3771 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3772 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3773 * Changes in other states are important on disabled stages too
3778 if(Type == WINED3DTSS_COLOROP) {
3781 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3782 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3783 * they have to be disabled
3785 * The current stage is dirtified below.
3787 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3788 TRACE("Additionally dirtifying stage %d\n", i);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3791 This->stateBlock->lowest_disabled_stage = Stage;
3792 TRACE("New lowest disabled: %d\n", Stage);
3793 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3794 /* Previously disabled stage enabled. Stages above it may need enabling
3795 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3796 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3798 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3801 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3802 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3805 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3806 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3808 This->stateBlock->lowest_disabled_stage = i;
3809 TRACE("New lowest disabled: %d\n", i);
3811 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3812 /* TODO: Built a stage -> texture unit mapping for register combiners */
3816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3818 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3819 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3820 * will call FindTexUnitMap too.
3822 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3823 IWineD3DDeviceImpl_FindTexUnitMap(This);
3828 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3830 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3831 *pValue = This->updateStateBlock->textureState[Stage][Type];
3838 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3841 IWineD3DBaseTexture *oldTexture;
3843 oldTexture = This->updateStateBlock->textures[Stage];
3844 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3846 #if 0 /* TODO: check so vertex textures */
3847 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3848 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3853 if(pTexture != NULL) {
3854 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3856 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3857 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3858 return WINED3DERR_INVALIDCALL;
3860 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3863 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3864 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3866 This->updateStateBlock->set.textures[Stage] = TRUE;
3867 This->updateStateBlock->changed.textures[Stage] = TRUE;
3868 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3869 This->updateStateBlock->textures[Stage] = pTexture;
3871 /* Handle recording of state blocks */
3872 if (This->isRecordingState) {
3873 TRACE("Recording... not performing anything\n");
3877 if(oldTexture == pTexture) {
3878 TRACE("App is setting the same texture again, nothing to do\n");
3882 /** NOTE: MSDN says that setTexture increases the reference count,
3883 * and the the application nust set the texture back to null (or have a leaky application),
3884 * This means we should pass the refcount up to the parent
3885 *******************************/
3886 if (NULL != This->updateStateBlock->textures[Stage]) {
3887 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3888 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3890 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3891 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3892 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3893 * so the COLOROP and ALPHAOP have to be dirtified.
3895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3898 if(bindCount == 1) {
3899 new->baseTexture.sampler = Stage;
3901 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3905 if (NULL != oldTexture) {
3906 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3907 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3909 IWineD3DBaseTexture_Release(oldTexture);
3910 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3915 if(bindCount && old->baseTexture.sampler == Stage) {
3917 /* Have to do a search for the other sampler(s) where the texture is bound to
3918 * Shouldn't happen as long as apps bind a texture only to one stage
3920 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3921 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3922 if(This->updateStateBlock->textures[i] == oldTexture) {
3923 old->baseTexture.sampler = i;
3930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3932 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3933 * pixel shader is used
3935 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3936 IWineD3DDeviceImpl_FindTexUnitMap(This);
3942 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3944 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3946 *ppTexture=This->stateBlock->textures[Stage];
3948 IWineD3DBaseTexture_AddRef(*ppTexture);
3956 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3957 IWineD3DSurface **ppBackBuffer) {
3958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3959 IWineD3DSwapChain *swapChain;
3962 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3964 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3965 if (hr == WINED3D_OK) {
3966 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3967 IWineD3DSwapChain_Release(swapChain);
3969 *ppBackBuffer = NULL;
3974 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3976 WARN("(%p) : stub, calling idirect3d for now\n", This);
3977 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3980 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3982 IWineD3DSwapChain *swapChain;
3985 if(iSwapChain > 0) {
3986 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3987 if (hr == WINED3D_OK) {
3988 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3989 IWineD3DSwapChain_Release(swapChain);
3991 FIXME("(%p) Error getting display mode\n", This);
3994 /* Don't read the real display mode,
3995 but return the stored mode instead. X11 can't change the color
3996 depth, and some apps are pretty angry if they SetDisplayMode from
3997 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3999 Also don't relay to the swapchain because with ddraw it's possible
4000 that there isn't a swapchain at all */
4001 pMode->Width = This->ddraw_width;
4002 pMode->Height = This->ddraw_height;
4003 pMode->Format = This->ddraw_format;
4004 pMode->RefreshRate = 0;
4011 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4013 TRACE("(%p)->(%p)\n", This, hWnd);
4015 if(This->ddraw_fullscreen) {
4016 if(This->ddraw_window && This->ddraw_window != hWnd) {
4017 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4019 if(hWnd && This->ddraw_window != hWnd) {
4020 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4024 This->ddraw_window = hWnd;
4028 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4030 TRACE("(%p)->(%p)\n", This, hWnd);
4032 *hWnd = This->ddraw_window;
4037 * Stateblock related functions
4040 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4042 IWineD3DStateBlockImpl *object;
4043 HRESULT temp_result;
4046 TRACE("(%p)\n", This);
4048 if (This->isRecordingState) {
4049 return WINED3DERR_INVALIDCALL;
4052 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4053 if (NULL == object ) {
4054 FIXME("(%p)Error allocating memory for stateblock\n", This);
4055 return E_OUTOFMEMORY;
4057 TRACE("(%p) created object %p\n", This, object);
4058 object->wineD3DDevice= This;
4059 /** FIXME: object->parent = parent; **/
4060 object->parent = NULL;
4061 object->blockType = WINED3DSBT_ALL;
4063 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4065 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4066 list_init(&object->lightMap[i]);
4069 temp_result = allocate_shader_constants(object);
4070 if (WINED3D_OK != temp_result)
4073 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4074 This->updateStateBlock = object;
4075 This->isRecordingState = TRUE;
4077 TRACE("(%p) recording stateblock %p\n",This , object);
4081 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4084 if (!This->isRecordingState) {
4085 FIXME("(%p) not recording! returning error\n", This);
4086 *ppStateBlock = NULL;
4087 return WINED3DERR_INVALIDCALL;
4090 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4091 This->isRecordingState = FALSE;
4092 This->updateStateBlock = This->stateBlock;
4093 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4094 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4095 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4100 * Scene related functions
4102 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4103 /* At the moment we have no need for any functionality at the beginning
4105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4106 TRACE("(%p)\n", This);
4109 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4110 return WINED3DERR_INVALIDCALL;
4112 This->inScene = TRUE;
4116 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 TRACE("(%p)\n", This);
4120 if(!This->inScene) {
4121 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4122 return WINED3DERR_INVALIDCALL;
4126 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4128 checkGLcall("glFlush");
4131 This->inScene = FALSE;
4135 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4136 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4137 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4139 IWineD3DSwapChain *swapChain = NULL;
4141 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4143 TRACE("(%p) Presenting the frame\n", This);
4145 for(i = 0 ; i < swapchains ; i ++) {
4147 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4148 TRACE("presentinng chain %d, %p\n", i, swapChain);
4149 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4150 IWineD3DSwapChain_Release(swapChain);
4156 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4157 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4160 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4161 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4162 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4163 GLbitfield glMask = 0;
4164 GLboolean old_ztest;
4165 GLfloat old_z_clear_value;
4166 GLint old_stencil_clear_value;
4167 GLfloat old_color_clear_value[4];
4169 CONST WINED3DRECT* curRect;
4171 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4172 Count, pRects, Flags, Z, Stencil);
4176 glEnable(GL_SCISSOR_TEST);
4177 checkGLcall("glEnable GL_SCISSOR_TEST");
4179 if (Count > 0 && pRects) {
4185 /* Only set the values up once, as they are not changing */
4186 if (Flags & WINED3DCLEAR_STENCIL) {
4187 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4188 glClearStencil(Stencil);
4189 checkGLcall("glClearStencil");
4190 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4191 glStencilMask(0xFFFFFFFF);
4194 if (Flags & WINED3DCLEAR_ZBUFFER) {
4195 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4196 glDepthMask(GL_TRUE);
4197 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4199 checkGLcall("glClearDepth");
4200 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4203 if (Flags & WINED3DCLEAR_TARGET) {
4204 TRACE("Clearing screen with glClear to color %x\n", Color);
4205 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4206 glClearColor(D3DCOLOR_R(Color),
4210 checkGLcall("glClearColor");
4212 /* Clear ALL colors! */
4213 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4214 glMask = glMask | GL_COLOR_BUFFER_BIT;
4217 /* Now process each rect in turn */
4218 for (i = 0; i < Count || i == 0; i++) {
4221 /* Note gl uses lower left, width/height */
4222 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4223 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4224 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4225 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4226 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4227 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4228 checkGLcall("glScissor");
4230 glScissor(This->stateBlock->viewport.X,
4231 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4232 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4233 This->stateBlock->viewport.Width,
4234 This->stateBlock->viewport.Height);
4235 checkGLcall("glScissor");
4238 /* Clear the selected rectangle (or full screen) */
4240 checkGLcall("glClear");
4242 /* Step to the next rectangle */
4243 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4246 /* Restore the old values (why..?) */
4247 if (Flags & WINED3DCLEAR_STENCIL) {
4248 glClearStencil(old_stencil_clear_value);
4249 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4251 if (Flags & WINED3DCLEAR_ZBUFFER) {
4252 glDepthMask(old_ztest);
4253 glClearDepth(old_z_clear_value);
4255 if (Flags & WINED3DCLEAR_TARGET) {
4256 glClearColor(old_color_clear_value[0],
4257 old_color_clear_value[1],
4258 old_color_clear_value[2],
4259 old_color_clear_value[3]);
4260 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4261 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4262 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4263 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4266 glDisable(GL_SCISSOR_TEST);
4267 checkGLcall("glDisable");
4270 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4271 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4273 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4280 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4281 UINT PrimitiveCount) {
4283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4284 This->stateBlock->streamIsUP = FALSE;
4286 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4287 debug_d3dprimitivetype(PrimitiveType),
4288 StartVertex, PrimitiveCount);
4290 if(This->stateBlock->loadBaseVertexIndex != 0) {
4291 This->stateBlock->loadBaseVertexIndex = 0;
4292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4294 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4295 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4296 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4300 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4301 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4302 WINED3DPRIMITIVETYPE PrimitiveType,
4303 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4307 IWineD3DIndexBuffer *pIB;
4308 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4311 pIB = This->stateBlock->pIndexData;
4312 This->stateBlock->streamIsUP = FALSE;
4313 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4315 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4316 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4317 minIndex, NumVertices, startIndex, primCount);
4319 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4320 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4326 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4327 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4331 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4332 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4337 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4338 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4339 UINT VertexStreamZeroStride) {
4340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4342 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4343 debug_d3dprimitivetype(PrimitiveType),
4344 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4346 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4347 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4348 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4349 This->stateBlock->streamIsUP = TRUE;
4350 This->stateBlock->loadBaseVertexIndex = 0;
4352 /* TODO: Only mark dirty if drawing from a different UP address */
4353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4355 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4356 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4358 /* MSDN specifies stream zero settings must be set to NULL */
4359 This->stateBlock->streamStride[0] = 0;
4360 This->stateBlock->streamSource[0] = NULL;
4362 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4363 * the new stream sources or use UP drawing again
4368 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4369 UINT MinVertexIndex, UINT NumVertices,
4370 UINT PrimitiveCount, CONST void* pIndexData,
4371 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4372 UINT VertexStreamZeroStride) {
4374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4376 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4377 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4378 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4379 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4381 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4387 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4388 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4389 This->stateBlock->streamIsUP = TRUE;
4390 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4392 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4393 This->stateBlock->baseVertexIndex = 0;
4394 This->stateBlock->loadBaseVertexIndex = 0;
4395 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4399 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4401 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4402 This->stateBlock->streamSource[0] = NULL;
4403 This->stateBlock->streamStride[0] = 0;
4404 This->stateBlock->pIndexData = NULL;
4405 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4406 * SetStreamSource to specify a vertex buffer
4412 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4415 /* Mark the state dirty until we have nicer tracking
4416 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4421 This->stateBlock->baseVertexIndex = 0;
4422 This->up_strided = DrawPrimStrideData;
4423 This->stateBlock->streamIsUP = TRUE;
4424 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4425 This->up_strided = NULL;
4428 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4429 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4431 HRESULT hr = WINED3D_OK;
4432 WINED3DRESOURCETYPE sourceType;
4433 WINED3DRESOURCETYPE destinationType;
4436 /* TODO: think about moving the code into IWineD3DBaseTexture */
4438 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4440 /* verify that the source and destination textures aren't NULL */
4441 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4442 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4443 This, pSourceTexture, pDestinationTexture);
4444 hr = WINED3DERR_INVALIDCALL;
4447 if (pSourceTexture == pDestinationTexture) {
4448 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4449 This, pSourceTexture, pDestinationTexture);
4450 hr = WINED3DERR_INVALIDCALL;
4452 /* Verify that the source and destination textures are the same type */
4453 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4454 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4456 if (sourceType != destinationType) {
4457 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4459 hr = WINED3DERR_INVALIDCALL;
4462 /* check that both textures have the identical numbers of levels */
4463 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4464 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4465 hr = WINED3DERR_INVALIDCALL;
4468 if (WINED3D_OK == hr) {
4470 /* Make sure that the destination texture is loaded */
4471 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4473 /* Update every surface level of the texture */
4474 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4476 switch (sourceType) {
4477 case WINED3DRTYPE_TEXTURE:
4479 IWineD3DSurface *srcSurface;
4480 IWineD3DSurface *destSurface;
4482 for (i = 0 ; i < levels ; ++i) {
4483 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4484 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4485 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4486 IWineD3DSurface_Release(srcSurface);
4487 IWineD3DSurface_Release(destSurface);
4488 if (WINED3D_OK != hr) {
4489 WARN("(%p) : Call to update surface failed\n", This);
4495 case WINED3DRTYPE_CUBETEXTURE:
4497 IWineD3DSurface *srcSurface;
4498 IWineD3DSurface *destSurface;
4499 WINED3DCUBEMAP_FACES faceType;
4501 for (i = 0 ; i < levels ; ++i) {
4502 /* Update each cube face */
4503 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4504 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4505 if (WINED3D_OK != hr) {
4506 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4508 TRACE("Got srcSurface %p\n", srcSurface);
4510 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4511 if (WINED3D_OK != hr) {
4512 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4514 TRACE("Got desrSurface %p\n", destSurface);
4516 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4517 IWineD3DSurface_Release(srcSurface);
4518 IWineD3DSurface_Release(destSurface);
4519 if (WINED3D_OK != hr) {
4520 WARN("(%p) : Call to update surface failed\n", This);
4527 #if 0 /* TODO: Add support for volume textures */
4528 case WINED3DRTYPE_VOLUMETEXTURE:
4530 IWineD3DVolume srcVolume = NULL;
4531 IWineD3DSurface destVolume = NULL;
4533 for (i = 0 ; i < levels ; ++i) {
4534 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4535 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4536 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4537 IWineD3DVolume_Release(srcSurface);
4538 IWineD3DVolume_Release(destSurface);
4539 if (WINED3D_OK != hr) {
4540 WARN("(%p) : Call to update volume failed\n", This);
4548 FIXME("(%p) : Unsupported source and destination type\n", This);
4549 hr = WINED3DERR_INVALIDCALL;
4556 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4557 IWineD3DSwapChain *swapChain;
4559 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4560 if(hr == WINED3D_OK) {
4561 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4562 IWineD3DSwapChain_Release(swapChain);
4567 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 /* return a sensible default */
4571 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4572 FIXME("(%p) : stub\n", This);
4576 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4580 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4581 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4582 return WINED3DERR_INVALIDCALL;
4584 for (j = 0; j < 256; ++j) {
4585 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4586 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4587 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4588 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4590 TRACE("(%p) : returning\n", This);
4594 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4597 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4598 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4599 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4600 return WINED3DERR_INVALIDCALL;
4602 for (j = 0; j < 256; ++j) {
4603 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4604 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4605 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4606 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4608 TRACE("(%p) : returning\n", This);
4612 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4614 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4615 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4616 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4617 return WINED3DERR_INVALIDCALL;
4619 /*TODO: stateblocks */
4620 This->currentPalette = PaletteNumber;
4621 TRACE("(%p) : returning\n", This);
4625 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4627 if (PaletteNumber == NULL) {
4628 WARN("(%p) : returning Invalid Call\n", This);
4629 return WINED3DERR_INVALIDCALL;
4631 /*TODO: stateblocks */
4632 *PaletteNumber = This->currentPalette;
4633 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4637 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4639 static BOOL showFixmes = TRUE;
4641 FIXME("(%p) : stub\n", This);
4645 This->softwareVertexProcessing = bSoftware;
4650 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4652 static BOOL showFixmes = TRUE;
4654 FIXME("(%p) : stub\n", This);
4657 return This->softwareVertexProcessing;
4661 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 IWineD3DSwapChain *swapChain;
4666 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4668 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4669 if(hr == WINED3D_OK){
4670 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4671 IWineD3DSwapChain_Release(swapChain);
4673 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4679 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4681 static BOOL showfixmes = TRUE;
4682 if(nSegments != 0.0f) {
4684 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4691 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4693 static BOOL showfixmes = TRUE;
4695 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4701 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4703 /** TODO: remove casts to IWineD3DSurfaceImpl
4704 * NOTE: move code to surface to accomplish this
4705 ****************************************/
4706 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4707 int srcWidth, srcHeight;
4708 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4709 WINED3DFORMAT destFormat, srcFormat;
4711 int srcLeft, destLeft, destTop;
4712 WINED3DPOOL srcPool, destPool;
4714 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4715 glDescriptor *glDescription = NULL;
4716 GLenum textureDimensions = GL_TEXTURE_2D;
4717 IWineD3DBaseTexture *baseTexture;
4719 WINED3DSURFACE_DESC winedesc;
4721 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4722 memset(&winedesc, 0, sizeof(winedesc));
4723 winedesc.Width = &srcSurfaceWidth;
4724 winedesc.Height = &srcSurfaceHeight;
4725 winedesc.Pool = &srcPool;
4726 winedesc.Format = &srcFormat;
4728 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4730 winedesc.Width = &destSurfaceWidth;
4731 winedesc.Height = &destSurfaceHeight;
4732 winedesc.Pool = &destPool;
4733 winedesc.Format = &destFormat;
4734 winedesc.Size = &destSize;
4736 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4738 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4739 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4740 return WINED3DERR_INVALIDCALL;
4743 if (destFormat == WINED3DFMT_UNKNOWN) {
4744 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4745 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4747 /* Get the update surface description */
4748 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4751 /* Make sure the surface is loaded and up to date */
4752 IWineD3DSurface_PreLoad(pDestinationSurface);
4754 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4758 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4759 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4760 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4761 srcLeft = pSourceRect ? pSourceRect->left : 0;
4762 destLeft = pDestPoint ? pDestPoint->x : 0;
4763 destTop = pDestPoint ? pDestPoint->y : 0;
4766 /* This function doesn't support compressed textures
4767 the pitch is just bytesPerPixel * width */
4768 if(srcWidth != srcSurfaceWidth || srcLeft ){
4769 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4770 offset += srcLeft * pSrcSurface->bytesPerPixel;
4771 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4773 /* TODO DXT formats */
4775 if(pSourceRect != NULL && pSourceRect->top != 0){
4776 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4778 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4780 ,glDescription->level
4785 ,glDescription->glFormat
4786 ,glDescription->glType
4787 ,IWineD3DSurface_GetData(pSourceSurface)
4791 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4793 /* need to lock the surface to get the data */
4794 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4797 /* TODO: Cube and volume support */
4799 /* not a whole row so we have to do it a line at a time */
4802 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4803 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4805 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4807 glTexSubImage2D(glDescription->target
4808 ,glDescription->level
4813 ,glDescription->glFormat
4814 ,glDescription->glType
4815 ,data /* could be quicker using */
4820 } else { /* Full width, so just write out the whole texture */
4822 if (WINED3DFMT_DXT1 == destFormat ||
4823 WINED3DFMT_DXT2 == destFormat ||
4824 WINED3DFMT_DXT3 == destFormat ||
4825 WINED3DFMT_DXT4 == destFormat ||
4826 WINED3DFMT_DXT5 == destFormat) {
4827 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4828 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4829 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4830 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4831 } if (destFormat != srcFormat) {
4832 FIXME("Updating mixed format compressed texture is not curretly support\n");
4834 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4835 glDescription->level,
4836 glDescription->glFormatInternal,
4841 IWineD3DSurface_GetData(pSourceSurface));
4844 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4849 glTexSubImage2D(glDescription->target
4850 ,glDescription->level
4855 ,glDescription->glFormat
4856 ,glDescription->glType
4857 ,IWineD3DSurface_GetData(pSourceSurface)
4861 checkGLcall("glTexSubImage2D");
4862 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4864 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4865 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4866 * surface bigger than it needs to be hmm.. */
4867 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4868 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4869 IWineD3DBaseTexture_Release(baseTexture);
4872 glDisable(textureDimensions); /* This needs to be managed better.... */
4878 /* Implementation details at http://developer.nvidia.com/attach/6494
4880 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4881 hmm.. no longer supported use
4882 OpenGL evaluators or tessellate surfaces within your application.
4885 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4886 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4888 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4889 FIXME("(%p) : Stub\n", This);
4894 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4895 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4898 FIXME("(%p) : Stub\n", This);
4902 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4904 TRACE("(%p) Handle(%d)\n", This, Handle);
4905 FIXME("(%p) : Stub\n", This);
4909 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4911 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4913 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4915 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4916 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4917 return WINED3DERR_INVALIDCALL;
4920 /* Just forward this to the DirectDraw blitting engine */
4921 memset(&BltFx, 0, sizeof(BltFx));
4922 BltFx.dwSize = sizeof(BltFx);
4923 BltFx.u5.dwFillColor = color;
4924 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4927 /* rendertarget and deptth stencil functions */
4928 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4931 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4932 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4933 return WINED3DERR_INVALIDCALL;
4936 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4937 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4938 /* Note inc ref on returned surface */
4939 if(*ppRenderTarget != NULL)
4940 IWineD3DSurface_AddRef(*ppRenderTarget);
4944 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4946 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4947 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4948 IWineD3DSwapChainImpl *Swapchain;
4951 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4953 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4954 if(hr != WINED3D_OK) {
4955 ERR("Can't get the swapchain\n");
4959 /* Make sure to release the swapchain */
4960 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4962 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4963 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4964 return WINED3DERR_INVALIDCALL;
4966 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4967 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4968 return WINED3DERR_INVALIDCALL;
4971 if(Swapchain->frontBuffer != Front) {
4972 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4974 if(Swapchain->frontBuffer)
4975 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4976 Swapchain->frontBuffer = Front;
4978 if(Swapchain->frontBuffer) {
4979 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4983 if(Back && !Swapchain->backBuffer) {
4984 /* We need memory for the back buffer array - only one back buffer this way */
4985 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4986 if(!Swapchain->backBuffer) {
4987 ERR("Out of memory\n");
4988 return E_OUTOFMEMORY;
4992 if(Swapchain->backBuffer[0] != Back) {
4993 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4995 if(!Swapchain->backBuffer[0]) {
4996 /* GL was told to draw to the front buffer at creation,
4999 glDrawBuffer(GL_BACK);
5000 checkGLcall("glDrawBuffer(GL_BACK)");
5001 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5002 Swapchain->presentParms.BackBufferCount = 1;
5004 /* That makes problems - disable for now */
5005 /* glDrawBuffer(GL_FRONT); */
5006 checkGLcall("glDrawBuffer(GL_FRONT)");
5007 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5008 Swapchain->presentParms.BackBufferCount = 0;
5012 if(Swapchain->backBuffer[0])
5013 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5014 Swapchain->backBuffer[0] = Back;
5016 if(Swapchain->backBuffer[0]) {
5017 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5019 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5027 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5029 *ppZStencilSurface = This->depthStencilBuffer;
5030 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5032 if(*ppZStencilSurface != NULL) {
5033 /* Note inc ref on returned surface */
5034 IWineD3DSurface_AddRef(*ppZStencilSurface);
5039 static void bind_fbo(IWineD3DDevice *iface) {
5040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5043 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5044 checkGLcall("glGenFramebuffersEXT()");
5046 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5047 checkGLcall("glBindFramebuffer()");
5050 /* TODO: Handle stencil attachments */
5051 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5053 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5055 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5059 if (depth_stencil_impl) {
5060 GLenum texttarget, target;
5061 GLint old_binding = 0;
5063 IWineD3DSurface_PreLoad(depth_stencil);
5064 texttarget = depth_stencil_impl->glDescription.target;
5065 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5067 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5068 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5069 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5070 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5071 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5072 glBindTexture(target, old_binding);
5074 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5075 checkGLcall("glFramebufferTexture2DEXT()");
5077 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5078 checkGLcall("glFramebufferTexture2DEXT()");
5081 if (!This->render_offscreen) {
5082 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5083 checkGLcall("glBindFramebuffer()");
5087 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5091 if (idx >= GL_LIMITS(buffers)) {
5092 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5098 GLenum texttarget, target;
5099 GLint old_binding = 0;
5101 IWineD3DSurface_PreLoad(render_target);
5102 texttarget = rtimpl->glDescription.target;
5103 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5105 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5106 glBindTexture(target, rtimpl->glDescription.textureName);
5107 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5108 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5109 glBindTexture(target, old_binding);
5111 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5112 checkGLcall("glFramebufferTexture2DEXT()");
5114 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5116 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5117 checkGLcall("glFramebufferTexture2DEXT()");
5119 This->draw_buffers[idx] = GL_NONE;
5122 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5123 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5124 checkGLcall("glDrawBuffers()");
5127 if (!This->render_offscreen) {
5128 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5129 checkGLcall("glBindFramebuffer()");
5133 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 WINED3DVIEWPORT viewport;
5137 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5139 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5140 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5141 return WINED3DERR_INVALIDCALL;
5144 /* MSDN says that null disables the render target
5145 but a device must always be associated with a render target
5146 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5148 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5151 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5152 FIXME("Trying to set render target 0 to NULL\n");
5153 return WINED3DERR_INVALIDCALL;
5155 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5156 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);
5157 return WINED3DERR_INVALIDCALL;
5160 /* If we are trying to set what we already have, don't bother */
5161 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5162 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5165 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5166 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5167 This->render_targets[RenderTargetIndex] = pRenderTarget;
5169 /* Render target 0 is special */
5170 if(RenderTargetIndex == 0) {
5171 /* Finally, reset the viewport as the MSDN states. */
5172 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5173 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5176 viewport.MaxZ = 1.0f;
5177 viewport.MinZ = 0.0f;
5178 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5180 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5182 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5183 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5185 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5187 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5188 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5193 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5195 HRESULT hr = WINED3D_OK;
5196 IWineD3DSurface *tmp;
5198 TRACE("(%p) Swapping z-buffer\n",This);
5200 if (pNewZStencil == This->stencilBufferTarget) {
5201 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5203 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5204 * depending on the renter target implementation being used.
5205 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5206 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5207 * stencil buffer and incure an extra memory overhead
5208 ******************************************************/
5211 tmp = This->stencilBufferTarget;
5212 This->stencilBufferTarget = pNewZStencil;
5213 /* should we be calling the parent or the wined3d surface? */
5214 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5215 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5217 /** TODO: glEnable/glDisable on depth/stencil depending on
5218 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5219 **********************************************************/
5220 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5221 set_depth_stencil_fbo(iface, pNewZStencil);
5228 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5229 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5231 /* TODO: the use of Impl is deprecated. */
5232 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5234 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5236 /* some basic validation checks */
5237 if(This->cursorTexture) {
5239 glDeleteTextures(1, &This->cursorTexture);
5241 This->cursorTexture = 0;
5245 /* MSDN: Cursor must be A8R8G8B8 */
5246 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5247 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5248 return WINED3DERR_INVALIDCALL;
5251 /* MSDN: Cursor must be smaller than the display mode */
5252 if(pSur->currentDesc.Width > This->ddraw_width ||
5253 pSur->currentDesc.Height > This->ddraw_height) {
5254 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);
5255 return WINED3DERR_INVALIDCALL;
5258 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5259 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5260 * Texture and Blitting code to draw the cursor
5262 pSur->Flags |= SFLAG_FORCELOAD;
5263 IWineD3DSurface_PreLoad(pCursorBitmap);
5264 pSur->Flags &= ~SFLAG_FORCELOAD;
5265 /* Do not store the surface's pointer because the application may release
5266 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5267 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5269 This->cursorTexture = pSur->glDescription.textureName;
5270 This->cursorWidth = pSur->currentDesc.Width;
5271 This->cursorHeight = pSur->currentDesc.Height;
5272 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5275 This->xHotSpot = XHotSpot;
5276 This->yHotSpot = YHotSpot;
5280 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5282 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5284 This->xScreenSpace = XScreenSpace;
5285 This->yScreenSpace = YScreenSpace;
5291 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5293 BOOL oldVisible = This->bCursorVisible;
5294 TRACE("(%p) : visible(%d)\n", This, bShow);
5296 if(This->cursorTexture)
5297 This->bCursorVisible = bShow;
5302 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5304 TRACE("(%p) : state (%u)\n", This, This->state);
5305 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5306 switch (This->state) {
5309 case WINED3DERR_DEVICELOST:
5311 ResourceList *resourceList = This->resources;
5312 while (NULL != resourceList) {
5313 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5314 return WINED3DERR_DEVICENOTRESET;
5315 resourceList = resourceList->next;
5317 return WINED3DERR_DEVICELOST;
5319 case WINED3DERR_DRIVERINTERNALERROR:
5320 return WINED3DERR_DRIVERINTERNALERROR;
5324 return WINED3DERR_DRIVERINTERNALERROR;
5328 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5330 /** FIXME: Resource tracking needs to be done,
5331 * The closes we can do to this is set the priorities of all managed textures low
5332 * and then reset them.
5333 ***********************************************************/
5334 FIXME("(%p) : stub\n", This);
5338 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5339 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5341 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5342 if(surface->Flags & SFLAG_DIBSECTION) {
5343 /* Release the DC */
5344 SelectObject(surface->hDC, surface->dib.holdbitmap);
5345 DeleteDC(surface->hDC);
5346 /* Release the DIB section */
5347 DeleteObject(surface->dib.DIBsection);
5348 surface->dib.bitmap_data = NULL;
5349 surface->resource.allocatedMemory = NULL;
5350 surface->Flags &= ~SFLAG_DIBSECTION;
5352 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5353 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5354 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5355 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5356 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5358 surface->pow2Width = surface->pow2Height = 1;
5359 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5360 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5362 if(surface->glDescription.textureName) {
5364 glDeleteTextures(1, &surface->glDescription.textureName);
5366 surface->glDescription.textureName = 0;
5368 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5369 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5370 surface->Flags |= SFLAG_NONPOW2;
5372 surface->Flags &= ~SFLAG_NONPOW2;
5374 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5375 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5378 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5380 IWineD3DSwapChainImpl *swapchain;
5382 BOOL DisplayModeChanged = FALSE;
5383 WINED3DDISPLAYMODE mode;
5384 TRACE("(%p)\n", This);
5386 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5388 ERR("Failed to get the first implicit swapchain\n");
5392 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5393 * on an existing gl context, so there's no real need for recreation.
5395 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5397 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5399 TRACE("New params:\n");
5400 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5401 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5402 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5403 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5404 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5405 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5406 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5407 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5408 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5409 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5410 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5411 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5412 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5414 /* No special treatment of these parameters. Just store them */
5415 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5416 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5417 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5418 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5420 /* What to do about these? */
5421 if(pPresentationParameters->BackBufferCount != 0 &&
5422 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5423 ERR("Cannot change the back buffer count yet\n");
5425 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5426 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5427 ERR("Cannot change the back buffer format yet\n");
5429 if(pPresentationParameters->hDeviceWindow != NULL &&
5430 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5431 ERR("Cannot change the device window yet\n");
5433 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5434 ERR("What do do about a changed auto depth stencil parameter?\n");
5437 if(pPresentationParameters->Windowed) {
5438 mode.Width = swapchain->orig_width;
5439 mode.Height = swapchain->orig_height;
5440 mode.RefreshRate = 0;
5441 mode.Format = swapchain->presentParms.BackBufferFormat;
5443 mode.Width = pPresentationParameters->BackBufferWidth;
5444 mode.Height = pPresentationParameters->BackBufferHeight;
5445 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5446 mode.Format = swapchain->presentParms.BackBufferFormat;
5449 /* Should Width == 800 && Height == 0 set 800x600? */
5450 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5451 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5452 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5459 vp.Width = pPresentationParameters->BackBufferWidth;
5460 vp.Height = pPresentationParameters->BackBufferHeight;
5464 if(!pPresentationParameters->Windowed) {
5465 DisplayModeChanged = TRUE;
5467 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5468 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5470 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5471 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5472 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5475 /* Now set the new viewport */
5476 IWineD3DDevice_SetViewport(iface, &vp);
5479 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5480 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5481 DisplayModeChanged) {
5483 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5484 if(!pPresentationParameters->Windowed) {
5485 IWineD3DDevice_SetFullscreen(iface, TRUE);
5488 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5490 /* Switching out of fullscreen mode? First set the original res, then change the window */
5491 if(pPresentationParameters->Windowed) {
5492 IWineD3DDevice_SetFullscreen(iface, FALSE);
5494 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5497 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5501 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5503 /** FIXME: always true at the moment **/
5504 if(!bEnableDialogs) {
5505 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5511 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5513 TRACE("(%p) : pParameters %p\n", This, pParameters);
5515 *pParameters = This->createParms;
5519 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5520 IWineD3DSwapChain *swapchain;
5521 HRESULT hrc = WINED3D_OK;
5523 TRACE("Relaying to swapchain\n");
5525 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5526 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5527 IWineD3DSwapChain_Release(swapchain);
5532 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5533 IWineD3DSwapChain *swapchain;
5534 HRESULT hrc = WINED3D_OK;
5536 TRACE("Relaying to swapchain\n");
5538 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5539 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5540 IWineD3DSwapChain_Release(swapchain);
5546 /** ********************************************************
5547 * Notification functions
5548 ** ********************************************************/
5549 /** This function must be called in the release of a resource when ref == 0,
5550 * the contents of resource must still be correct,
5551 * any handels to other resource held by the caller must be closed
5552 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5553 *****************************************************/
5554 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5556 ResourceList* resourceList;
5558 TRACE("(%p) : resource %p\n", This, resource);
5560 EnterCriticalSection(&resourceStoreCriticalSection);
5562 /* add a new texture to the frot of the linked list */
5563 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5564 resourceList->resource = resource;
5566 /* Get the old head */
5567 resourceList->next = This->resources;
5569 This->resources = resourceList;
5570 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5573 LeaveCriticalSection(&resourceStoreCriticalSection);
5578 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5580 ResourceList* resourceList = NULL;
5581 ResourceList* previousResourceList = NULL;
5583 TRACE("(%p) : resource %p\n", This, resource);
5586 EnterCriticalSection(&resourceStoreCriticalSection);
5588 resourceList = This->resources;
5590 while (resourceList != NULL) {
5591 if(resourceList->resource == resource) break;
5592 previousResourceList = resourceList;
5593 resourceList = resourceList->next;
5596 if (resourceList == NULL) {
5597 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5599 LeaveCriticalSection(&resourceStoreCriticalSection);
5603 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5605 /* make sure we don't leave a hole in the list */
5606 if (previousResourceList != NULL) {
5607 previousResourceList->next = resourceList->next;
5609 This->resources = resourceList->next;
5613 LeaveCriticalSection(&resourceStoreCriticalSection);
5619 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5623 TRACE("(%p) : resource %p\n", This, resource);
5624 switch(IWineD3DResource_GetType(resource)){
5625 case WINED3DRTYPE_SURFACE:
5626 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5628 case WINED3DRTYPE_TEXTURE:
5629 case WINED3DRTYPE_CUBETEXTURE:
5630 case WINED3DRTYPE_VOLUMETEXTURE:
5631 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5632 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5633 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5634 This->stateBlock->textures[counter] = NULL;
5636 if (This->updateStateBlock != This->stateBlock ){
5637 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5638 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5639 This->updateStateBlock->textures[counter] = NULL;
5644 case WINED3DRTYPE_VOLUME:
5645 /* TODO: nothing really? */
5647 case WINED3DRTYPE_VERTEXBUFFER:
5648 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5651 TRACE("Cleaning up stream pointers\n");
5653 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5654 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5655 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5657 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5658 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5659 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5660 This->updateStateBlock->streamSource[streamNumber] = 0;
5661 /* Set changed flag? */
5664 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) */
5665 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5666 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5667 This->stateBlock->streamSource[streamNumber] = 0;
5670 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5671 else { /* This shouldn't happen */
5672 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5679 case WINED3DRTYPE_INDEXBUFFER:
5680 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5681 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5682 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5683 This->updateStateBlock->pIndexData = NULL;
5686 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5687 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5688 This->stateBlock->pIndexData = NULL;
5694 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5699 /* Remove the resoruce from the resourceStore */
5700 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5702 TRACE("Resource released\n");
5706 /**********************************************************
5707 * IWineD3DDevice VTbl follows
5708 **********************************************************/
5710 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5712 /*** IUnknown methods ***/
5713 IWineD3DDeviceImpl_QueryInterface,
5714 IWineD3DDeviceImpl_AddRef,
5715 IWineD3DDeviceImpl_Release,
5716 /*** IWineD3DDevice methods ***/
5717 IWineD3DDeviceImpl_GetParent,
5718 /*** Creation methods**/
5719 IWineD3DDeviceImpl_CreateVertexBuffer,
5720 IWineD3DDeviceImpl_CreateIndexBuffer,
5721 IWineD3DDeviceImpl_CreateStateBlock,
5722 IWineD3DDeviceImpl_CreateSurface,
5723 IWineD3DDeviceImpl_CreateTexture,
5724 IWineD3DDeviceImpl_CreateVolumeTexture,
5725 IWineD3DDeviceImpl_CreateVolume,
5726 IWineD3DDeviceImpl_CreateCubeTexture,
5727 IWineD3DDeviceImpl_CreateQuery,
5728 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5729 IWineD3DDeviceImpl_CreateVertexDeclaration,
5730 IWineD3DDeviceImpl_CreateVertexShader,
5731 IWineD3DDeviceImpl_CreatePixelShader,
5732 IWineD3DDeviceImpl_CreatePalette,
5733 /*** Odd functions **/
5734 IWineD3DDeviceImpl_Init3D,
5735 IWineD3DDeviceImpl_Uninit3D,
5736 IWineD3DDeviceImpl_SetFullscreen,
5737 IWineD3DDeviceImpl_EvictManagedResources,
5738 IWineD3DDeviceImpl_GetAvailableTextureMem,
5739 IWineD3DDeviceImpl_GetBackBuffer,
5740 IWineD3DDeviceImpl_GetCreationParameters,
5741 IWineD3DDeviceImpl_GetDeviceCaps,
5742 IWineD3DDeviceImpl_GetDirect3D,
5743 IWineD3DDeviceImpl_GetDisplayMode,
5744 IWineD3DDeviceImpl_SetDisplayMode,
5745 IWineD3DDeviceImpl_GetHWND,
5746 IWineD3DDeviceImpl_SetHWND,
5747 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5748 IWineD3DDeviceImpl_GetRasterStatus,
5749 IWineD3DDeviceImpl_GetSwapChain,
5750 IWineD3DDeviceImpl_Reset,
5751 IWineD3DDeviceImpl_SetDialogBoxMode,
5752 IWineD3DDeviceImpl_SetCursorProperties,
5753 IWineD3DDeviceImpl_SetCursorPosition,
5754 IWineD3DDeviceImpl_ShowCursor,
5755 IWineD3DDeviceImpl_TestCooperativeLevel,
5756 /*** Getters and setters **/
5757 IWineD3DDeviceImpl_SetClipPlane,
5758 IWineD3DDeviceImpl_GetClipPlane,
5759 IWineD3DDeviceImpl_SetClipStatus,
5760 IWineD3DDeviceImpl_GetClipStatus,
5761 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5762 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5763 IWineD3DDeviceImpl_SetDepthStencilSurface,
5764 IWineD3DDeviceImpl_GetDepthStencilSurface,
5765 IWineD3DDeviceImpl_SetFVF,
5766 IWineD3DDeviceImpl_GetFVF,
5767 IWineD3DDeviceImpl_SetGammaRamp,
5768 IWineD3DDeviceImpl_GetGammaRamp,
5769 IWineD3DDeviceImpl_SetIndices,
5770 IWineD3DDeviceImpl_GetIndices,
5771 IWineD3DDeviceImpl_SetBasevertexIndex,
5772 IWineD3DDeviceImpl_SetLight,
5773 IWineD3DDeviceImpl_GetLight,
5774 IWineD3DDeviceImpl_SetLightEnable,
5775 IWineD3DDeviceImpl_GetLightEnable,
5776 IWineD3DDeviceImpl_SetMaterial,
5777 IWineD3DDeviceImpl_GetMaterial,
5778 IWineD3DDeviceImpl_SetNPatchMode,
5779 IWineD3DDeviceImpl_GetNPatchMode,
5780 IWineD3DDeviceImpl_SetPaletteEntries,
5781 IWineD3DDeviceImpl_GetPaletteEntries,
5782 IWineD3DDeviceImpl_SetPixelShader,
5783 IWineD3DDeviceImpl_GetPixelShader,
5784 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5785 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5786 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5787 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5788 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5789 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5790 IWineD3DDeviceImpl_SetRenderState,
5791 IWineD3DDeviceImpl_GetRenderState,
5792 IWineD3DDeviceImpl_SetRenderTarget,
5793 IWineD3DDeviceImpl_GetRenderTarget,
5794 IWineD3DDeviceImpl_SetFrontBackBuffers,
5795 IWineD3DDeviceImpl_SetSamplerState,
5796 IWineD3DDeviceImpl_GetSamplerState,
5797 IWineD3DDeviceImpl_SetScissorRect,
5798 IWineD3DDeviceImpl_GetScissorRect,
5799 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5800 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5801 IWineD3DDeviceImpl_SetStreamSource,
5802 IWineD3DDeviceImpl_GetStreamSource,
5803 IWineD3DDeviceImpl_SetStreamSourceFreq,
5804 IWineD3DDeviceImpl_GetStreamSourceFreq,
5805 IWineD3DDeviceImpl_SetTexture,
5806 IWineD3DDeviceImpl_GetTexture,
5807 IWineD3DDeviceImpl_SetTextureStageState,
5808 IWineD3DDeviceImpl_GetTextureStageState,
5809 IWineD3DDeviceImpl_SetTransform,
5810 IWineD3DDeviceImpl_GetTransform,
5811 IWineD3DDeviceImpl_SetVertexDeclaration,
5812 IWineD3DDeviceImpl_GetVertexDeclaration,
5813 IWineD3DDeviceImpl_SetVertexShader,
5814 IWineD3DDeviceImpl_GetVertexShader,
5815 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5816 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5817 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5818 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5819 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5820 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5821 IWineD3DDeviceImpl_SetViewport,
5822 IWineD3DDeviceImpl_GetViewport,
5823 IWineD3DDeviceImpl_MultiplyTransform,
5824 IWineD3DDeviceImpl_ValidateDevice,
5825 IWineD3DDeviceImpl_ProcessVertices,
5826 /*** State block ***/
5827 IWineD3DDeviceImpl_BeginStateBlock,
5828 IWineD3DDeviceImpl_EndStateBlock,
5829 /*** Scene management ***/
5830 IWineD3DDeviceImpl_BeginScene,
5831 IWineD3DDeviceImpl_EndScene,
5832 IWineD3DDeviceImpl_Present,
5833 IWineD3DDeviceImpl_Clear,
5835 IWineD3DDeviceImpl_DrawPrimitive,
5836 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5837 IWineD3DDeviceImpl_DrawPrimitiveUP,
5838 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5839 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5840 IWineD3DDeviceImpl_DrawRectPatch,
5841 IWineD3DDeviceImpl_DrawTriPatch,
5842 IWineD3DDeviceImpl_DeletePatch,
5843 IWineD3DDeviceImpl_ColorFill,
5844 IWineD3DDeviceImpl_UpdateTexture,
5845 IWineD3DDeviceImpl_UpdateSurface,
5846 IWineD3DDeviceImpl_GetFrontBufferData,
5847 /*** object tracking ***/
5848 IWineD3DDeviceImpl_ResourceReleased
5852 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5853 WINED3DRS_ALPHABLENDENABLE ,
5854 WINED3DRS_ALPHAFUNC ,
5855 WINED3DRS_ALPHAREF ,
5856 WINED3DRS_ALPHATESTENABLE ,
5858 WINED3DRS_COLORWRITEENABLE ,
5859 WINED3DRS_DESTBLEND ,
5860 WINED3DRS_DITHERENABLE ,
5861 WINED3DRS_FILLMODE ,
5862 WINED3DRS_FOGDENSITY ,
5864 WINED3DRS_FOGSTART ,
5865 WINED3DRS_LASTPIXEL ,
5866 WINED3DRS_SHADEMODE ,
5867 WINED3DRS_SRCBLEND ,
5868 WINED3DRS_STENCILENABLE ,
5869 WINED3DRS_STENCILFAIL ,
5870 WINED3DRS_STENCILFUNC ,
5871 WINED3DRS_STENCILMASK ,
5872 WINED3DRS_STENCILPASS ,
5873 WINED3DRS_STENCILREF ,
5874 WINED3DRS_STENCILWRITEMASK ,
5875 WINED3DRS_STENCILZFAIL ,
5876 WINED3DRS_TEXTUREFACTOR ,
5887 WINED3DRS_ZWRITEENABLE
5890 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5891 WINED3DTSS_ADDRESSW ,
5892 WINED3DTSS_ALPHAARG0 ,
5893 WINED3DTSS_ALPHAARG1 ,
5894 WINED3DTSS_ALPHAARG2 ,
5895 WINED3DTSS_ALPHAOP ,
5896 WINED3DTSS_BUMPENVLOFFSET ,
5897 WINED3DTSS_BUMPENVLSCALE ,
5898 WINED3DTSS_BUMPENVMAT00 ,
5899 WINED3DTSS_BUMPENVMAT01 ,
5900 WINED3DTSS_BUMPENVMAT10 ,
5901 WINED3DTSS_BUMPENVMAT11 ,
5902 WINED3DTSS_COLORARG0 ,
5903 WINED3DTSS_COLORARG1 ,
5904 WINED3DTSS_COLORARG2 ,
5905 WINED3DTSS_COLOROP ,
5906 WINED3DTSS_RESULTARG ,
5907 WINED3DTSS_TEXCOORDINDEX ,
5908 WINED3DTSS_TEXTURETRANSFORMFLAGS
5911 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5912 WINED3DSAMP_ADDRESSU ,
5913 WINED3DSAMP_ADDRESSV ,
5914 WINED3DSAMP_ADDRESSW ,
5915 WINED3DSAMP_BORDERCOLOR ,
5916 WINED3DSAMP_MAGFILTER ,
5917 WINED3DSAMP_MINFILTER ,
5918 WINED3DSAMP_MIPFILTER ,
5919 WINED3DSAMP_MIPMAPLODBIAS ,
5920 WINED3DSAMP_MAXMIPLEVEL ,
5921 WINED3DSAMP_MAXANISOTROPY ,
5922 WINED3DSAMP_SRGBTEXTURE ,
5923 WINED3DSAMP_ELEMENTINDEX
5926 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5928 WINED3DRS_AMBIENTMATERIALSOURCE ,
5929 WINED3DRS_CLIPPING ,
5930 WINED3DRS_CLIPPLANEENABLE ,
5931 WINED3DRS_COLORVERTEX ,
5932 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5933 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5934 WINED3DRS_FOGDENSITY ,
5936 WINED3DRS_FOGSTART ,
5937 WINED3DRS_FOGTABLEMODE ,
5938 WINED3DRS_FOGVERTEXMODE ,
5939 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5940 WINED3DRS_LIGHTING ,
5941 WINED3DRS_LOCALVIEWER ,
5942 WINED3DRS_MULTISAMPLEANTIALIAS ,
5943 WINED3DRS_MULTISAMPLEMASK ,
5944 WINED3DRS_NORMALIZENORMALS ,
5945 WINED3DRS_PATCHEDGESTYLE ,
5946 WINED3DRS_POINTSCALE_A ,
5947 WINED3DRS_POINTSCALE_B ,
5948 WINED3DRS_POINTSCALE_C ,
5949 WINED3DRS_POINTSCALEENABLE ,
5950 WINED3DRS_POINTSIZE ,
5951 WINED3DRS_POINTSIZE_MAX ,
5952 WINED3DRS_POINTSIZE_MIN ,
5953 WINED3DRS_POINTSPRITEENABLE ,
5954 WINED3DRS_RANGEFOGENABLE ,
5955 WINED3DRS_SPECULARMATERIALSOURCE ,
5956 WINED3DRS_TWEENFACTOR ,
5957 WINED3DRS_VERTEXBLEND
5960 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5961 WINED3DTSS_TEXCOORDINDEX ,
5962 WINED3DTSS_TEXTURETRANSFORMFLAGS
5965 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5966 WINED3DSAMP_DMAPOFFSET
5969 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5970 DWORD rep = StateTable[state].representative;
5974 WineD3DContext *context;
5977 for(i = 0; i < This->numContexts; i++) {
5978 context = This->contexts[i];
5979 if(isStateDirty(context, rep)) continue;
5981 context->dirtyArray[context->numDirtyEntries++] = rep;
5984 context->isStateDirty[idx] |= (1 << shift);