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 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2203 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2204 if(object->OriginalIndex == Index) break;
2209 TRACE("Adding new light\n");
2210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2212 ERR("Out of memory error when allocating a light\n");
2213 return E_OUTOFMEMORY;
2215 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2216 object->glIndex = -1;
2217 object->OriginalIndex = Index;
2218 object->changed = TRUE;
2221 /* Initialize the object */
2222 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,
2223 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2224 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2225 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2226 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2227 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2228 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2230 /* Save away the information */
2231 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2233 switch (pLight->Type) {
2234 case WINED3DLIGHT_POINT:
2236 object->lightPosn[0] = pLight->Position.x;
2237 object->lightPosn[1] = pLight->Position.y;
2238 object->lightPosn[2] = pLight->Position.z;
2239 object->lightPosn[3] = 1.0f;
2240 object->cutoff = 180.0f;
2244 case WINED3DLIGHT_DIRECTIONAL:
2246 object->lightPosn[0] = -pLight->Direction.x;
2247 object->lightPosn[1] = -pLight->Direction.y;
2248 object->lightPosn[2] = -pLight->Direction.z;
2249 object->lightPosn[3] = 0.0;
2250 object->exponent = 0.0f;
2251 object->cutoff = 180.0f;
2254 case WINED3DLIGHT_SPOT:
2256 object->lightPosn[0] = pLight->Position.x;
2257 object->lightPosn[1] = pLight->Position.y;
2258 object->lightPosn[2] = pLight->Position.z;
2259 object->lightPosn[3] = 1.0;
2262 object->lightDirn[0] = pLight->Direction.x;
2263 object->lightDirn[1] = pLight->Direction.y;
2264 object->lightDirn[2] = pLight->Direction.z;
2265 object->lightDirn[3] = 1.0;
2268 * opengl-ish and d3d-ish spot lights use too different models for the
2269 * light "intensity" as a function of the angle towards the main light direction,
2270 * so we only can approximate very roughly.
2271 * however spot lights are rather rarely used in games (if ever used at all).
2272 * furthermore if still used, probably nobody pays attention to such details.
2274 if (pLight->Falloff == 0) {
2277 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2279 if (rho < 0.0001) rho = 0.0001f;
2280 object->exponent = -0.3/log(cos(rho/2));
2281 if (object->exponent > 128.0) {
2282 object->exponent = 128.0;
2284 object->cutoff = pLight->Phi*90/M_PI;
2290 FIXME("Unrecognized light type %d\n", pLight->Type);
2293 /* Update the live definitions if the light is currently assigned a glIndex */
2294 if (object->glIndex != -1 && !This->isRecordingState) {
2295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2300 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2301 PLIGHTINFOEL *lightInfo = NULL;
2302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2303 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2305 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2307 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2308 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2309 if(lightInfo->OriginalIndex == Index) break;
2313 if (lightInfo == NULL) {
2314 TRACE("Light information requested but light not defined\n");
2315 return WINED3DERR_INVALIDCALL;
2318 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2323 * Get / Set Light Enable
2324 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2326 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2327 PLIGHTINFOEL *lightInfo = NULL;
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2331 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2333 /* Tests show true = 128...not clear why */
2334 Enable = Enable? 128: 0;
2336 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2337 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2338 if(lightInfo->OriginalIndex == Index) break;
2341 TRACE("Found light: %p\n", lightInfo);
2343 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2344 if (lightInfo == NULL) {
2346 TRACE("Light enabled requested but light not defined, so defining one!\n");
2347 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2349 /* Search for it again! Should be fairly quick as near head of list */
2350 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2351 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2352 if(lightInfo->OriginalIndex == Index) break;
2355 if (lightInfo == NULL) {
2356 FIXME("Adding default lights has failed dismally\n");
2357 return WINED3DERR_INVALIDCALL;
2361 lightInfo->enabledChanged = TRUE;
2363 if(lightInfo->glIndex != -1) {
2364 if(!This->isRecordingState) {
2365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2368 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2369 lightInfo->glIndex = -1;
2371 TRACE("Light already disabled, nothing to do\n");
2374 if (lightInfo->glIndex != -1) {
2376 TRACE("Nothing to do as light was enabled\n");
2379 /* Find a free gl light */
2380 for(i = 0; i < This->maxConcurrentLights; i++) {
2381 if(This->stateBlock->activeLights[i] == NULL) {
2382 This->stateBlock->activeLights[i] = lightInfo;
2383 lightInfo->glIndex = i;
2387 if(lightInfo->glIndex == -1) {
2388 ERR("Too many concurrently active lights\n");
2389 return WINED3DERR_INVALIDCALL;
2392 /* i == lightInfo->glIndex */
2393 if(!This->isRecordingState) {
2394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2402 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2404 PLIGHTINFOEL *lightInfo = NULL;
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2407 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2408 TRACE("(%p) : for idx(%d)\n", This, Index);
2410 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2411 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2412 if(lightInfo->OriginalIndex == Index) break;
2416 if (lightInfo == NULL) {
2417 TRACE("Light enabled state requested but light not defined\n");
2418 return WINED3DERR_INVALIDCALL;
2420 /* true is 128 according to SetLightEnable */
2421 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2426 * Get / Set Clip Planes
2428 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2432 /* Validate Index */
2433 if (Index >= GL_LIMITS(clipplanes)) {
2434 TRACE("Application has requested clipplane this device doesn't support\n");
2435 return WINED3DERR_INVALIDCALL;
2438 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2439 This->updateStateBlock->set.clipplane[Index] = TRUE;
2440 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2441 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2442 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2443 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2445 /* Handle recording of state blocks */
2446 if (This->isRecordingState) {
2447 TRACE("Recording... not performing anything\n");
2455 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2456 glMatrixMode(GL_MODELVIEW);
2458 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2460 TRACE("Clipplane [%f,%f,%f,%f]\n",
2461 This->updateStateBlock->clipplane[Index][0],
2462 This->updateStateBlock->clipplane[Index][1],
2463 This->updateStateBlock->clipplane[Index][2],
2464 This->updateStateBlock->clipplane[Index][3]);
2465 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2466 checkGLcall("glClipPlane");
2474 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2476 TRACE("(%p) : for idx %d\n", This, Index);
2478 /* Validate Index */
2479 if (Index >= GL_LIMITS(clipplanes)) {
2480 TRACE("Application has requested clipplane this device doesn't support\n");
2481 return WINED3DERR_INVALIDCALL;
2484 pPlane[0] = This->stateBlock->clipplane[Index][0];
2485 pPlane[1] = This->stateBlock->clipplane[Index][1];
2486 pPlane[2] = This->stateBlock->clipplane[Index][2];
2487 pPlane[3] = This->stateBlock->clipplane[Index][3];
2492 * Get / Set Clip Plane Status
2493 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2495 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2497 FIXME("(%p) : stub\n", This);
2498 if (NULL == pClipStatus) {
2499 return WINED3DERR_INVALIDCALL;
2501 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2502 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2506 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2508 FIXME("(%p) : stub\n", This);
2509 if (NULL == pClipStatus) {
2510 return WINED3DERR_INVALIDCALL;
2512 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2513 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2518 * Get / Set Material
2520 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 This->updateStateBlock->changed.material = TRUE;
2524 This->updateStateBlock->set.material = TRUE;
2525 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2527 /* Handle recording of state blocks */
2528 if (This->isRecordingState) {
2529 TRACE("Recording... not performing anything\n");
2534 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2535 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2536 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2537 pMaterial->Ambient.b, pMaterial->Ambient.a);
2538 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2539 pMaterial->Specular.b, pMaterial->Specular.a);
2540 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2541 pMaterial->Emissive.b, pMaterial->Emissive.a);
2542 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2544 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2545 checkGLcall("glMaterialfv(GL_AMBIENT)");
2546 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2547 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2549 /* Only change material color if specular is enabled, otherwise it is set to black */
2550 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2551 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2552 checkGLcall("glMaterialfv(GL_SPECULAR");
2554 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2555 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2556 checkGLcall("glMaterialfv(GL_SPECULAR");
2558 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2559 checkGLcall("glMaterialfv(GL_EMISSION)");
2560 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2561 checkGLcall("glMaterialf(GL_SHININESS");
2567 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2569 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2570 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2571 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2572 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2573 pMaterial->Ambient.b, pMaterial->Ambient.a);
2574 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2575 pMaterial->Specular.b, pMaterial->Specular.a);
2576 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2577 pMaterial->Emissive.b, pMaterial->Emissive.a);
2578 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2586 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2587 UINT BaseVertexIndex) {
2588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 IWineD3DIndexBuffer *oldIdxs;
2590 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2592 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2593 oldIdxs = This->updateStateBlock->pIndexData;
2595 This->updateStateBlock->changed.indices = TRUE;
2596 This->updateStateBlock->set.indices = TRUE;
2597 This->updateStateBlock->pIndexData = pIndexData;
2598 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2600 /* Handle recording of state blocks */
2601 if (This->isRecordingState) {
2602 TRACE("Recording... not performing anything\n");
2606 /* The base vertex index affects the stream sources, while
2607 * The index buffer is a seperate index buffer state
2609 if(BaseVertexIndex != oldBaseIndex) {
2610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2612 if(oldIdxs != pIndexData) {
2613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2618 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 *ppIndexData = This->stateBlock->pIndexData;
2623 /* up ref count on ppindexdata */
2625 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2626 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2627 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2629 TRACE("(%p) No index data set\n", This);
2631 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2636 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2637 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 TRACE("(%p)->(%d)\n", This, BaseIndex);
2641 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2642 TRACE("Application is setting the old value over, nothing to do\n");
2646 This->updateStateBlock->baseVertexIndex = BaseIndex;
2648 if (This->isRecordingState) {
2649 TRACE("Recording... not performing anything\n");
2652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2657 * Get / Set Viewports
2659 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 TRACE("(%p)\n", This);
2663 This->updateStateBlock->changed.viewport = TRUE;
2664 This->updateStateBlock->set.viewport = TRUE;
2665 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2667 /* Handle recording of state blocks */
2668 if (This->isRecordingState) {
2669 TRACE("Recording... not performing anything\n");
2673 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2674 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2681 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 TRACE("(%p)\n", This);
2684 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2689 * Get / Set Render States
2690 * TODO: Verify against dx9 definitions
2692 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2695 DWORD oldValue = This->stateBlock->renderState[State];
2697 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2699 This->updateStateBlock->changed.renderState[State] = TRUE;
2700 This->updateStateBlock->set.renderState[State] = TRUE;
2701 This->updateStateBlock->renderState[State] = Value;
2703 /* Handle recording of state blocks */
2704 if (This->isRecordingState) {
2705 TRACE("Recording... not performing anything\n");
2709 /* Compared here and not before the assignment to allow proper stateblock recording */
2710 if(Value == oldValue) {
2711 TRACE("Application is setting the old value over, nothing to do\n");
2713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2719 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2722 *pValue = This->stateBlock->renderState[State];
2727 * Get / Set Sampler States
2728 * TODO: Verify against dx9 definitions
2731 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2733 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2736 * SetSampler is designed to allow for more than the standard up to 8 textures
2737 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2738 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2740 * http://developer.nvidia.com/object/General_FAQ.html#t6
2742 * There are two new settings for GForce
2744 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2745 * and the texture one:
2746 * GL_MAX_TEXTURE_COORDS_ARB.
2747 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2750 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2751 debug_d3dsamplerstate(Type), Type, Value);
2752 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2753 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2754 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2756 /* Handle recording of state blocks */
2757 if (This->isRecordingState) {
2758 TRACE("Recording... not performing anything\n");
2762 if(oldValue == Value) {
2763 TRACE("Application is setting the old value over, nothing to do\n");
2767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2772 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2774 *Value = This->stateBlock->samplerState[Sampler][Type];
2775 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2780 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2783 This->updateStateBlock->set.scissorRect = TRUE;
2784 This->updateStateBlock->changed.scissorRect = TRUE;
2785 if(memcmp(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect)) == 0) {
2786 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2789 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2791 if(This->isRecordingState) {
2792 TRACE("Recording... not performing anything\n");
2796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2801 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2805 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2811 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2813 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2815 This->updateStateBlock->vertexDecl = pDecl;
2816 This->updateStateBlock->changed.vertexDecl = TRUE;
2817 This->updateStateBlock->set.vertexDecl = TRUE;
2819 if (This->isRecordingState) {
2820 TRACE("Recording... not performing anything\n");
2822 } else if(pDecl == oldDecl) {
2823 /* Checked after the assignment to allow proper stateblock recording */
2824 TRACE("Application is setting the old declaration over, nothing to do\n");
2828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2832 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2837 *ppDecl = This->stateBlock->vertexDecl;
2838 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2842 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2844 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2846 This->updateStateBlock->vertexShader = pShader;
2847 This->updateStateBlock->changed.vertexShader = TRUE;
2848 This->updateStateBlock->set.vertexShader = TRUE;
2850 if (This->isRecordingState) {
2851 TRACE("Recording... not performing anything\n");
2853 } else if(oldShader == pShader) {
2854 /* Checked here to allow proper stateblock recording */
2855 TRACE("App is setting the old shader over, nothing to do\n");
2859 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2866 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 if (NULL == ppShader) {
2870 return WINED3DERR_INVALIDCALL;
2872 *ppShader = This->stateBlock->vertexShader;
2873 if( NULL != *ppShader)
2874 IWineD3DVertexShader_AddRef(*ppShader);
2876 TRACE("(%p) : returning %p\n", This, *ppShader);
2880 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2881 IWineD3DDevice *iface,
2883 CONST BOOL *srcData,
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 int i, cnt = min(count, MAX_CONST_B - start);
2889 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2890 iface, srcData, start, count);
2892 if (srcData == NULL || cnt < 0)
2893 return WINED3DERR_INVALIDCALL;
2895 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2896 for (i = 0; i < cnt; i++)
2897 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2899 for (i = start; i < cnt + start; ++i) {
2900 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2901 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2909 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2910 IWineD3DDevice *iface,
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2916 int cnt = min(count, MAX_CONST_B - start);
2918 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2919 iface, dstData, start, count);
2921 if (dstData == NULL || cnt < 0)
2922 return WINED3DERR_INVALIDCALL;
2924 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2928 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2929 IWineD3DDevice *iface,
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 int i, cnt = min(count, MAX_CONST_I - start);
2937 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2938 iface, srcData, start, count);
2940 if (srcData == NULL || cnt < 0)
2941 return WINED3DERR_INVALIDCALL;
2943 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2944 for (i = 0; i < cnt; i++)
2945 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2946 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2948 for (i = start; i < cnt + start; ++i) {
2949 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2950 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2958 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2959 IWineD3DDevice *iface,
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2965 int cnt = min(count, MAX_CONST_I - start);
2967 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2968 iface, dstData, start, count);
2970 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2971 return WINED3DERR_INVALIDCALL;
2973 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2977 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2978 IWineD3DDevice *iface,
2980 CONST float *srcData,
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2986 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2987 iface, srcData, start, count);
2989 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
2990 return WINED3DERR_INVALIDCALL;
2992 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
2993 for (i = 0; i < cnt; i++)
2994 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2995 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2997 for (i = start; i < cnt + start; ++i) {
2998 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
2999 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3001 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3002 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3004 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3012 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3013 IWineD3DDevice *iface,
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3019 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3021 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3022 iface, dstData, start, count);
3024 if (dstData == NULL || cnt < 0)
3025 return WINED3DERR_INVALIDCALL;
3027 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3031 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3033 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3038 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3040 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3041 * it is never called.
3044 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3045 * that would be really messy and require shader recompilation
3046 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3047 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3048 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3049 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3051 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3052 if(This->oneToOneTexUnitMap) {
3053 TRACE("Not touching 1:1 map\n");
3056 TRACE("Restoring 1:1 texture unit mapping\n");
3057 /* Restore a 1:1 mapping */
3058 for(i = 0; i < MAX_SAMPLERS; i++) {
3059 if(This->texUnitMap[i] != i) {
3060 This->texUnitMap[i] = i;
3061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3062 markTextureStagesDirty(This, i);
3065 This->oneToOneTexUnitMap = TRUE;
3068 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3069 * First, see if we can succeed at all
3072 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3073 if(This->stateBlock->textures[i] == NULL) tex++;
3076 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3077 FIXME("Too many bound textures to support the combiner settings\n");
3081 /* Now work out the mapping */
3083 This->oneToOneTexUnitMap = FALSE;
3084 WARN("Non 1:1 mapping UNTESTED!\n");
3085 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3086 /* Skip NULL textures */
3087 if (!This->stateBlock->textures[i]) {
3088 /* Map to -1, so the check below doesn't fail if a non-NULL
3089 * texture is set on this stage */
3090 TRACE("Mapping texture stage %d to -1\n", i);
3091 This->texUnitMap[i] = -1;
3096 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3097 if(This->texUnitMap[i] != tex) {
3098 This->texUnitMap[i] = tex;
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3100 markTextureStagesDirty(This, i);
3108 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3111 This->updateStateBlock->pixelShader = pShader;
3112 This->updateStateBlock->changed.pixelShader = TRUE;
3113 This->updateStateBlock->set.pixelShader = TRUE;
3115 /* Handle recording of state blocks */
3116 if (This->isRecordingState) {
3117 TRACE("Recording... not performing anything\n");
3120 if (This->isRecordingState) {
3121 TRACE("Recording... not performing anything\n");
3125 if(pShader == oldShader) {
3126 TRACE("App is setting the old pixel shader over, nothing to do\n");
3130 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3133 /* Rebuild the texture unit mapping if nvrc's are supported */
3134 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3135 IWineD3DDeviceImpl_FindTexUnitMap(This);
3141 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 if (NULL == ppShader) {
3145 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3146 return WINED3DERR_INVALIDCALL;
3149 *ppShader = This->stateBlock->pixelShader;
3150 if (NULL != *ppShader) {
3151 IWineD3DPixelShader_AddRef(*ppShader);
3153 TRACE("(%p) : returning %p\n", This, *ppShader);
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3158 IWineD3DDevice *iface,
3160 CONST BOOL *srcData,
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 int i, cnt = min(count, MAX_CONST_B - start);
3166 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3167 iface, srcData, start, count);
3169 if (srcData == NULL || cnt < 0)
3170 return WINED3DERR_INVALIDCALL;
3172 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3173 for (i = 0; i < cnt; i++)
3174 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3176 for (i = start; i < cnt + start; ++i) {
3177 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3178 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3186 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3187 IWineD3DDevice *iface,
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 int cnt = min(count, MAX_CONST_B - start);
3195 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3196 iface, dstData, start, count);
3198 if (dstData == NULL || cnt < 0)
3199 return WINED3DERR_INVALIDCALL;
3201 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3206 IWineD3DDevice *iface,
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 int i, cnt = min(count, MAX_CONST_I - start);
3214 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3215 iface, srcData, start, count);
3217 if (srcData == NULL || cnt < 0)
3218 return WINED3DERR_INVALIDCALL;
3220 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3221 for (i = 0; i < cnt; i++)
3222 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3223 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3225 for (i = start; i < cnt + start; ++i) {
3226 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3227 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3235 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3236 IWineD3DDevice *iface,
3241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 int cnt = min(count, MAX_CONST_I - start);
3244 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3245 iface, dstData, start, count);
3247 if (dstData == NULL || cnt < 0)
3248 return WINED3DERR_INVALIDCALL;
3250 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3254 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3255 IWineD3DDevice *iface,
3257 CONST float *srcData,
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3263 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3264 iface, srcData, start, count);
3266 if (srcData == NULL || cnt < 0)
3267 return WINED3DERR_INVALIDCALL;
3269 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3270 for (i = 0; i < cnt; i++)
3271 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3272 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3274 for (i = start; i < cnt + start; ++i) {
3275 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3276 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3278 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3279 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3281 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3290 IWineD3DDevice *iface,
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3298 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3299 iface, dstData, start, count);
3301 if (dstData == NULL || cnt < 0)
3302 return WINED3DERR_INVALIDCALL;
3304 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3308 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3310 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3311 char *dest_ptr, *dest_conv = NULL;
3313 DWORD DestFVF = dest->fvf;
3315 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3319 if (SrcFVF & WINED3DFVF_NORMAL) {
3320 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3323 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3324 ERR("Source has no position mask\n");
3325 return WINED3DERR_INVALIDCALL;
3328 /* We might access VBOs from this code, so hold the lock */
3331 if (dest->resource.allocatedMemory == NULL) {
3332 /* This may happen if we do direct locking into a vbo. Unlikely,
3333 * but theoretically possible(ddraw processvertices test)
3335 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3336 if(!dest->resource.allocatedMemory) {
3338 ERR("Out of memory\n");
3339 return E_OUTOFMEMORY;
3343 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3344 checkGLcall("glBindBufferARB");
3345 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3347 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3349 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3350 checkGLcall("glUnmapBufferARB");
3354 /* Get a pointer into the destination vbo(create one if none exists) and
3355 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3357 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3362 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3363 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3365 ERR("glMapBuffer failed\n");
3366 /* Continue without storing converted vertices */
3371 * a) WINED3DRS_CLIPPING is enabled
3372 * b) WINED3DVOP_CLIP is passed
3374 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3375 static BOOL warned = FALSE;
3377 * The clipping code is not quite correct. Some things need
3378 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3379 * so disable clipping for now.
3380 * (The graphics in Half-Life are broken, and my processvertices
3381 * test crashes with IDirect3DDevice3)
3387 FIXME("Clipping is broken and disabled for now\n");
3389 } else doClip = FALSE;
3390 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3392 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3395 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3398 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3399 WINED3DTS_PROJECTION,
3401 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3402 WINED3DTS_WORLDMATRIX(0),
3405 TRACE("View mat:\n");
3406 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);
3407 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);
3408 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);
3409 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);
3411 TRACE("Proj mat:\n");
3412 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);
3413 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);
3414 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);
3415 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);
3417 TRACE("World mat:\n");
3418 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);
3419 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);
3420 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);
3421 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);
3423 /* Get the viewport */
3424 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3425 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3426 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3428 multiply_matrix(&mat,&view_mat,&world_mat);
3429 multiply_matrix(&mat,&proj_mat,&mat);
3431 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3433 for (i = 0; i < dwCount; i+= 1) {
3434 unsigned int tex_index;
3436 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3437 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3438 /* The position first */
3440 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3442 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3444 /* Multiplication with world, view and projection matrix */
3445 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);
3446 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);
3447 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);
3448 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);
3450 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3452 /* WARNING: The following things are taken from d3d7 and were not yet checked
3453 * against d3d8 or d3d9!
3456 /* Clipping conditions: From
3457 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3459 * A vertex is clipped if it does not match the following requirements
3463 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3465 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3466 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3471 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3472 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3475 /* "Normal" viewport transformation (not clipped)
3476 * 1) The values are divided by rhw
3477 * 2) The y axis is negative, so multiply it with -1
3478 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3479 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3480 * 4) Multiply x with Width/2 and add Width/2
3481 * 5) The same for the height
3482 * 6) Add the viewpoint X and Y to the 2D coordinates and
3483 * The minimum Z value to z
3484 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3486 * Well, basically it's simply a linear transformation into viewport
3498 z *= vp.MaxZ - vp.MinZ;
3500 x += vp.Width / 2 + vp.X;
3501 y += vp.Height / 2 + vp.Y;
3506 /* That vertex got clipped
3507 * Contrary to OpenGL it is not dropped completely, it just
3508 * undergoes a different calculation.
3510 TRACE("Vertex got clipped\n");
3517 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3518 * outside of the main vertex buffer memory. That needs some more
3523 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3526 ( (float *) dest_ptr)[0] = x;
3527 ( (float *) dest_ptr)[1] = y;
3528 ( (float *) dest_ptr)[2] = z;
3529 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3531 dest_ptr += 3 * sizeof(float);
3533 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3534 dest_ptr += sizeof(float);
3539 ( (float *) dest_conv)[0] = x * w;
3540 ( (float *) dest_conv)[1] = y * w;
3541 ( (float *) dest_conv)[2] = z * w;
3542 ( (float *) dest_conv)[3] = w;
3544 dest_conv += 3 * sizeof(float);
3546 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3547 dest_conv += sizeof(float);
3551 if (DestFVF & WINED3DFVF_PSIZE) {
3552 dest_ptr += sizeof(DWORD);
3553 if(dest_conv) dest_conv += sizeof(DWORD);
3555 if (DestFVF & WINED3DFVF_NORMAL) {
3557 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3558 /* AFAIK this should go into the lighting information */
3559 FIXME("Didn't expect the destination to have a normal\n");
3560 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3562 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3566 if (DestFVF & WINED3DFVF_DIFFUSE) {
3568 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3570 static BOOL warned = FALSE;
3573 ERR("No diffuse color in source, but destination has one\n");
3577 *( (DWORD *) dest_ptr) = 0xffffffff;
3578 dest_ptr += sizeof(DWORD);
3581 *( (DWORD *) dest_conv) = 0xffffffff;
3582 dest_conv += sizeof(DWORD);
3586 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3588 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3589 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3590 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3591 dest_conv += sizeof(DWORD);
3596 if (DestFVF & WINED3DFVF_SPECULAR) {
3597 /* What's the color value in the feedback buffer? */
3599 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3601 static BOOL warned = FALSE;
3604 ERR("No specular color in source, but destination has one\n");
3608 *( (DWORD *) dest_ptr) = 0xFF000000;
3609 dest_ptr += sizeof(DWORD);
3612 *( (DWORD *) dest_conv) = 0xFF000000;
3613 dest_conv += sizeof(DWORD);
3617 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3619 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3620 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3621 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3622 dest_conv += sizeof(DWORD);
3627 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3629 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3630 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3632 ERR("No source texture, but destination requests one\n");
3633 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3634 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3637 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3639 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3646 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3647 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3654 #undef copy_and_next
3656 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3658 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3659 WineDirect3DVertexStridedData strided;
3660 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3663 WARN("NULL source vertex buffer\n");
3664 return WINED3DERR_INVALIDCALL;
3666 /* We don't need the source vbo because this buffer is only used as
3667 * a source for ProcessVertices. Avoid wasting resources by converting the
3668 * buffer and loading the VBO
3671 TRACE("Releasing the source vbo, it won't be needed\n");
3673 if(!SrcImpl->resource.allocatedMemory) {
3674 /* Rescue the data from the buffer */
3676 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3677 if(!SrcImpl->resource.allocatedMemory) {
3678 ERR("Out of memory\n");
3679 return E_OUTOFMEMORY;
3683 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3684 checkGLcall("glBindBufferARB");
3686 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3688 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3691 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3692 checkGLcall("glUnmapBufferARB");
3697 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3698 checkGLcall("glBindBufferARB");
3699 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3700 checkGLcall("glDeleteBuffersARB");
3706 memset(&strided, 0, sizeof(strided));
3707 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3709 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3713 * Get / Set Texture Stage States
3714 * TODO: Verify against dx9 definitions
3716 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3718 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3720 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3722 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3724 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3725 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3726 This->updateStateBlock->textureState[Stage][Type] = Value;
3728 if (This->isRecordingState) {
3729 TRACE("Recording... not performing anything\n");
3733 /* Checked after the assignments to allow proper stateblock recording */
3734 if(oldValue == Value) {
3735 TRACE("App is setting the old value over, nothing to do\n");
3739 if(Stage > This->stateBlock->lowest_disabled_stage &&
3740 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3741 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3742 * Changes in other states are important on disabled stages too
3747 if(Type == WINED3DTSS_COLOROP) {
3750 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3751 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3752 * they have to be disabled
3754 * The current stage is dirtified below.
3756 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3757 TRACE("Additionally dirtifying stage %d\n", i);
3758 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3760 This->stateBlock->lowest_disabled_stage = Stage;
3761 TRACE("New lowest disabled: %d\n", Stage);
3762 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3763 /* Previously disabled stage enabled. Stages above it may need enabling
3764 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3765 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3767 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3770 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3771 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3774 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3777 This->stateBlock->lowest_disabled_stage = i;
3778 TRACE("New lowest disabled: %d\n", i);
3780 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3781 /* TODO: Built a stage -> texture unit mapping for register combiners */
3785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3787 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3788 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3789 * will call FindTexUnitMap too.
3791 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3792 IWineD3DDeviceImpl_FindTexUnitMap(This);
3797 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3799 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3800 *pValue = This->updateStateBlock->textureState[Stage][Type];
3807 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3810 IWineD3DBaseTexture *oldTexture;
3812 oldTexture = This->updateStateBlock->textures[Stage];
3813 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3815 #if 0 /* TODO: check so vertex textures */
3816 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3817 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3822 if(pTexture != NULL) {
3823 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3825 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3826 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3827 return WINED3DERR_INVALIDCALL;
3829 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3832 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3833 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3835 This->updateStateBlock->set.textures[Stage] = TRUE;
3836 This->updateStateBlock->changed.textures[Stage] = TRUE;
3837 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3838 This->updateStateBlock->textures[Stage] = pTexture;
3840 /* Handle recording of state blocks */
3841 if (This->isRecordingState) {
3842 TRACE("Recording... not performing anything\n");
3846 if(oldTexture == pTexture) {
3847 TRACE("App is setting the same texture again, nothing to do\n");
3851 /** NOTE: MSDN says that setTexture increases the reference count,
3852 * and the the application nust set the texture back to null (or have a leaky application),
3853 * This means we should pass the refcount up to the parent
3854 *******************************/
3855 if (NULL != This->updateStateBlock->textures[Stage]) {
3856 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3857 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3859 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3860 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3861 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3862 * so the COLOROP and ALPHAOP have to be dirtified.
3864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3867 if(bindCount == 1) {
3868 new->baseTexture.sampler = Stage;
3870 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3874 if (NULL != oldTexture) {
3875 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3876 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3878 IWineD3DBaseTexture_Release(oldTexture);
3879 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3884 if(bindCount && old->baseTexture.sampler == Stage) {
3886 /* Have to do a search for the other sampler(s) where the texture is bound to
3887 * Shouldn't happen as long as apps bind a texture only to one stage
3889 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3890 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3891 if(This->updateStateBlock->textures[i] == oldTexture) {
3892 old->baseTexture.sampler = i;
3899 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3901 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3902 * pixel shader is used
3904 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3905 IWineD3DDeviceImpl_FindTexUnitMap(This);
3911 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3913 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3915 *ppTexture=This->stateBlock->textures[Stage];
3917 IWineD3DBaseTexture_AddRef(*ppTexture);
3925 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3926 IWineD3DSurface **ppBackBuffer) {
3927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3928 IWineD3DSwapChain *swapChain;
3931 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3933 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3934 if (hr == WINED3D_OK) {
3935 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3936 IWineD3DSwapChain_Release(swapChain);
3938 *ppBackBuffer = NULL;
3943 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 WARN("(%p) : stub, calling idirect3d for now\n", This);
3946 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3949 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3951 IWineD3DSwapChain *swapChain;
3954 if(iSwapChain > 0) {
3955 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3956 if (hr == WINED3D_OK) {
3957 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3958 IWineD3DSwapChain_Release(swapChain);
3960 FIXME("(%p) Error getting display mode\n", This);
3963 /* Don't read the real display mode,
3964 but return the stored mode instead. X11 can't change the color
3965 depth, and some apps are pretty angry if they SetDisplayMode from
3966 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3968 Also don't relay to the swapchain because with ddraw it's possible
3969 that there isn't a swapchain at all */
3970 pMode->Width = This->ddraw_width;
3971 pMode->Height = This->ddraw_height;
3972 pMode->Format = This->ddraw_format;
3973 pMode->RefreshRate = 0;
3980 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
3981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3982 TRACE("(%p)->(%p)\n", This, hWnd);
3984 if(This->ddraw_fullscreen) {
3985 if(This->ddraw_window && This->ddraw_window != hWnd) {
3986 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
3988 if(hWnd && This->ddraw_window != hWnd) {
3989 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
3993 This->ddraw_window = hWnd;
3997 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
3998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3999 TRACE("(%p)->(%p)\n", This, hWnd);
4001 *hWnd = This->ddraw_window;
4006 * Stateblock related functions
4009 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4011 IWineD3DStateBlockImpl *object;
4012 HRESULT temp_result;
4015 TRACE("(%p)\n", This);
4017 if (This->isRecordingState) {
4018 return WINED3DERR_INVALIDCALL;
4021 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4022 if (NULL == object ) {
4023 FIXME("(%p)Error allocating memory for stateblock\n", This);
4024 return E_OUTOFMEMORY;
4026 TRACE("(%p) created object %p\n", This, object);
4027 object->wineD3DDevice= This;
4028 /** FIXME: object->parent = parent; **/
4029 object->parent = NULL;
4030 object->blockType = WINED3DSBT_ALL;
4032 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4034 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4035 list_init(&object->lightMap[i]);
4038 temp_result = allocate_shader_constants(object);
4039 if (WINED3D_OK != temp_result)
4042 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4043 This->updateStateBlock = object;
4044 This->isRecordingState = TRUE;
4046 TRACE("(%p) recording stateblock %p\n",This , object);
4050 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053 if (!This->isRecordingState) {
4054 FIXME("(%p) not recording! returning error\n", This);
4055 *ppStateBlock = NULL;
4056 return WINED3DERR_INVALIDCALL;
4059 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4060 This->isRecordingState = FALSE;
4061 This->updateStateBlock = This->stateBlock;
4062 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4063 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4064 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4069 * Scene related functions
4071 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4072 /* At the moment we have no need for any functionality at the beginning
4074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4075 TRACE("(%p)\n", This);
4078 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4079 return WINED3DERR_INVALIDCALL;
4081 This->inScene = TRUE;
4085 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4087 TRACE("(%p)\n", This);
4089 if(!This->inScene) {
4090 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4091 return WINED3DERR_INVALIDCALL;
4095 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4097 checkGLcall("glFlush");
4100 This->inScene = FALSE;
4104 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4105 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4106 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4108 IWineD3DSwapChain *swapChain = NULL;
4110 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4112 TRACE("(%p) Presenting the frame\n", This);
4114 for(i = 0 ; i < swapchains ; i ++) {
4116 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4117 TRACE("presentinng chain %d, %p\n", i, swapChain);
4118 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4119 IWineD3DSwapChain_Release(swapChain);
4125 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4126 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4129 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4130 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4131 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4132 GLbitfield glMask = 0;
4133 GLboolean old_ztest;
4134 GLfloat old_z_clear_value;
4135 GLint old_stencil_clear_value;
4136 GLfloat old_color_clear_value[4];
4138 CONST WINED3DRECT* curRect;
4140 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4141 Count, pRects, Flags, Z, Stencil);
4145 glEnable(GL_SCISSOR_TEST);
4146 checkGLcall("glEnable GL_SCISSOR_TEST");
4148 if (Count > 0 && pRects) {
4154 /* Only set the values up once, as they are not changing */
4155 if (Flags & WINED3DCLEAR_STENCIL) {
4156 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4157 glClearStencil(Stencil);
4158 checkGLcall("glClearStencil");
4159 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4160 glStencilMask(0xFFFFFFFF);
4163 if (Flags & WINED3DCLEAR_ZBUFFER) {
4164 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4165 glDepthMask(GL_TRUE);
4166 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4168 checkGLcall("glClearDepth");
4169 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4172 if (Flags & WINED3DCLEAR_TARGET) {
4173 TRACE("Clearing screen with glClear to color %x\n", Color);
4174 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4175 glClearColor(D3DCOLOR_R(Color),
4179 checkGLcall("glClearColor");
4181 /* Clear ALL colors! */
4182 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4183 glMask = glMask | GL_COLOR_BUFFER_BIT;
4186 /* Now process each rect in turn */
4187 for (i = 0; i < Count || i == 0; i++) {
4190 /* Note gl uses lower left, width/height */
4191 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4192 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4193 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4194 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4195 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4196 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4197 checkGLcall("glScissor");
4199 glScissor(This->stateBlock->viewport.X,
4200 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4201 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4202 This->stateBlock->viewport.Width,
4203 This->stateBlock->viewport.Height);
4204 checkGLcall("glScissor");
4207 /* Clear the selected rectangle (or full screen) */
4209 checkGLcall("glClear");
4211 /* Step to the next rectangle */
4212 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4215 /* Restore the old values (why..?) */
4216 if (Flags & WINED3DCLEAR_STENCIL) {
4217 glClearStencil(old_stencil_clear_value);
4218 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4220 if (Flags & WINED3DCLEAR_ZBUFFER) {
4221 glDepthMask(old_ztest);
4222 glClearDepth(old_z_clear_value);
4224 if (Flags & WINED3DCLEAR_TARGET) {
4225 glClearColor(old_color_clear_value[0],
4226 old_color_clear_value[1],
4227 old_color_clear_value[2],
4228 old_color_clear_value[3]);
4229 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4230 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4231 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4232 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4235 glDisable(GL_SCISSOR_TEST);
4236 checkGLcall("glDisable");
4239 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4240 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4242 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4249 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4250 UINT PrimitiveCount) {
4252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4253 This->stateBlock->streamIsUP = FALSE;
4255 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4256 debug_d3dprimitivetype(PrimitiveType),
4257 StartVertex, PrimitiveCount);
4259 if(This->stateBlock->loadBaseVertexIndex != 0) {
4260 This->stateBlock->loadBaseVertexIndex = 0;
4261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4263 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4264 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4265 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4269 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4271 WINED3DPRIMITIVETYPE PrimitiveType,
4272 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4276 IWineD3DIndexBuffer *pIB;
4277 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4280 pIB = This->stateBlock->pIndexData;
4281 This->stateBlock->streamIsUP = FALSE;
4282 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4284 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4285 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4286 minIndex, NumVertices, startIndex, primCount);
4288 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4289 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4295 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4296 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4300 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4301 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4306 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4307 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4308 UINT VertexStreamZeroStride) {
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4311 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4312 debug_d3dprimitivetype(PrimitiveType),
4313 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4315 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4316 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4317 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4318 This->stateBlock->streamIsUP = TRUE;
4319 This->stateBlock->loadBaseVertexIndex = 0;
4321 /* TODO: Only mark dirty if drawing from a different UP address */
4322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4324 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4325 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4327 /* MSDN specifies stream zero settings must be set to NULL */
4328 This->stateBlock->streamStride[0] = 0;
4329 This->stateBlock->streamSource[0] = NULL;
4331 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4332 * the new stream sources or use UP drawing again
4337 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4338 UINT MinVertexIndex, UINT NumVertices,
4339 UINT PrimitiveCount, CONST void* pIndexData,
4340 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4341 UINT VertexStreamZeroStride) {
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4345 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4346 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4347 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4348 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4350 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4356 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4357 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4358 This->stateBlock->streamIsUP = TRUE;
4359 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4361 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4362 This->stateBlock->baseVertexIndex = 0;
4363 This->stateBlock->loadBaseVertexIndex = 0;
4364 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4368 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4370 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4371 This->stateBlock->streamSource[0] = NULL;
4372 This->stateBlock->streamStride[0] = 0;
4373 This->stateBlock->pIndexData = NULL;
4374 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4375 * SetStreamSource to specify a vertex buffer
4381 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4384 /* Mark the state dirty until we have nicer tracking
4385 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4390 This->stateBlock->baseVertexIndex = 0;
4391 This->up_strided = DrawPrimStrideData;
4392 This->stateBlock->streamIsUP = TRUE;
4393 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4394 This->up_strided = NULL;
4397 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4398 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4400 HRESULT hr = WINED3D_OK;
4401 WINED3DRESOURCETYPE sourceType;
4402 WINED3DRESOURCETYPE destinationType;
4405 /* TODO: think about moving the code into IWineD3DBaseTexture */
4407 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4409 /* verify that the source and destination textures aren't NULL */
4410 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4411 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4412 This, pSourceTexture, pDestinationTexture);
4413 hr = WINED3DERR_INVALIDCALL;
4416 if (pSourceTexture == pDestinationTexture) {
4417 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4418 This, pSourceTexture, pDestinationTexture);
4419 hr = WINED3DERR_INVALIDCALL;
4421 /* Verify that the source and destination textures are the same type */
4422 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4423 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4425 if (sourceType != destinationType) {
4426 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4428 hr = WINED3DERR_INVALIDCALL;
4431 /* check that both textures have the identical numbers of levels */
4432 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4433 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4434 hr = WINED3DERR_INVALIDCALL;
4437 if (WINED3D_OK == hr) {
4439 /* Make sure that the destination texture is loaded */
4440 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4442 /* Update every surface level of the texture */
4443 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4445 switch (sourceType) {
4446 case WINED3DRTYPE_TEXTURE:
4448 IWineD3DSurface *srcSurface;
4449 IWineD3DSurface *destSurface;
4451 for (i = 0 ; i < levels ; ++i) {
4452 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4453 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4454 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4455 IWineD3DSurface_Release(srcSurface);
4456 IWineD3DSurface_Release(destSurface);
4457 if (WINED3D_OK != hr) {
4458 WARN("(%p) : Call to update surface failed\n", This);
4464 case WINED3DRTYPE_CUBETEXTURE:
4466 IWineD3DSurface *srcSurface;
4467 IWineD3DSurface *destSurface;
4468 WINED3DCUBEMAP_FACES faceType;
4470 for (i = 0 ; i < levels ; ++i) {
4471 /* Update each cube face */
4472 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4473 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4474 if (WINED3D_OK != hr) {
4475 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4477 TRACE("Got srcSurface %p\n", srcSurface);
4479 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4480 if (WINED3D_OK != hr) {
4481 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4483 TRACE("Got desrSurface %p\n", 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);
4496 #if 0 /* TODO: Add support for volume textures */
4497 case WINED3DRTYPE_VOLUMETEXTURE:
4499 IWineD3DVolume srcVolume = NULL;
4500 IWineD3DSurface destVolume = NULL;
4502 for (i = 0 ; i < levels ; ++i) {
4503 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4504 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4505 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4506 IWineD3DVolume_Release(srcSurface);
4507 IWineD3DVolume_Release(destSurface);
4508 if (WINED3D_OK != hr) {
4509 WARN("(%p) : Call to update volume failed\n", This);
4517 FIXME("(%p) : Unsupported source and destination type\n", This);
4518 hr = WINED3DERR_INVALIDCALL;
4525 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4526 IWineD3DSwapChain *swapChain;
4528 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4529 if(hr == WINED3D_OK) {
4530 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4531 IWineD3DSwapChain_Release(swapChain);
4536 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 /* return a sensible default */
4540 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4541 FIXME("(%p) : stub\n", This);
4545 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4548 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4549 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4550 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4551 return WINED3DERR_INVALIDCALL;
4553 for (j = 0; j < 256; ++j) {
4554 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4555 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4556 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4557 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4559 TRACE("(%p) : returning\n", This);
4563 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4567 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4568 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4569 return WINED3DERR_INVALIDCALL;
4571 for (j = 0; j < 256; ++j) {
4572 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4573 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4574 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4575 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4577 TRACE("(%p) : returning\n", This);
4581 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4584 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4585 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4586 return WINED3DERR_INVALIDCALL;
4588 /*TODO: stateblocks */
4589 This->currentPalette = PaletteNumber;
4590 TRACE("(%p) : returning\n", This);
4594 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4596 if (PaletteNumber == NULL) {
4597 WARN("(%p) : returning Invalid Call\n", This);
4598 return WINED3DERR_INVALIDCALL;
4600 /*TODO: stateblocks */
4601 *PaletteNumber = This->currentPalette;
4602 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4606 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 static BOOL showFixmes = TRUE;
4610 FIXME("(%p) : stub\n", This);
4614 This->softwareVertexProcessing = bSoftware;
4619 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4621 static BOOL showFixmes = TRUE;
4623 FIXME("(%p) : stub\n", This);
4626 return This->softwareVertexProcessing;
4630 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4632 IWineD3DSwapChain *swapChain;
4635 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4637 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4638 if(hr == WINED3D_OK){
4639 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4640 IWineD3DSwapChain_Release(swapChain);
4642 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4648 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 static BOOL showfixmes = TRUE;
4651 if(nSegments != 0.0f) {
4653 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4660 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 static BOOL showfixmes = TRUE;
4664 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4670 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4672 /** TODO: remove casts to IWineD3DSurfaceImpl
4673 * NOTE: move code to surface to accomplish this
4674 ****************************************/
4675 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4676 int srcWidth, srcHeight;
4677 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4678 WINED3DFORMAT destFormat, srcFormat;
4680 int srcLeft, destLeft, destTop;
4681 WINED3DPOOL srcPool, destPool;
4683 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4684 glDescriptor *glDescription = NULL;
4685 GLenum textureDimensions = GL_TEXTURE_2D;
4686 IWineD3DBaseTexture *baseTexture;
4688 WINED3DSURFACE_DESC winedesc;
4690 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4691 memset(&winedesc, 0, sizeof(winedesc));
4692 winedesc.Width = &srcSurfaceWidth;
4693 winedesc.Height = &srcSurfaceHeight;
4694 winedesc.Pool = &srcPool;
4695 winedesc.Format = &srcFormat;
4697 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4699 winedesc.Width = &destSurfaceWidth;
4700 winedesc.Height = &destSurfaceHeight;
4701 winedesc.Pool = &destPool;
4702 winedesc.Format = &destFormat;
4703 winedesc.Size = &destSize;
4705 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4707 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4708 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4709 return WINED3DERR_INVALIDCALL;
4712 if (destFormat == WINED3DFMT_UNKNOWN) {
4713 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4714 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4716 /* Get the update surface description */
4717 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4720 /* Make sure the surface is loaded and up to date */
4721 IWineD3DSurface_PreLoad(pDestinationSurface);
4723 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4727 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4728 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4729 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4730 srcLeft = pSourceRect ? pSourceRect->left : 0;
4731 destLeft = pDestPoint ? pDestPoint->x : 0;
4732 destTop = pDestPoint ? pDestPoint->y : 0;
4735 /* This function doesn't support compressed textures
4736 the pitch is just bytesPerPixel * width */
4737 if(srcWidth != srcSurfaceWidth || srcLeft ){
4738 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4739 offset += srcLeft * pSrcSurface->bytesPerPixel;
4740 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4742 /* TODO DXT formats */
4744 if(pSourceRect != NULL && pSourceRect->top != 0){
4745 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4747 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4749 ,glDescription->level
4754 ,glDescription->glFormat
4755 ,glDescription->glType
4756 ,IWineD3DSurface_GetData(pSourceSurface)
4760 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4762 /* need to lock the surface to get the data */
4763 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4766 /* TODO: Cube and volume support */
4768 /* not a whole row so we have to do it a line at a time */
4771 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4772 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4774 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4776 glTexSubImage2D(glDescription->target
4777 ,glDescription->level
4782 ,glDescription->glFormat
4783 ,glDescription->glType
4784 ,data /* could be quicker using */
4789 } else { /* Full width, so just write out the whole texture */
4791 if (WINED3DFMT_DXT1 == destFormat ||
4792 WINED3DFMT_DXT2 == destFormat ||
4793 WINED3DFMT_DXT3 == destFormat ||
4794 WINED3DFMT_DXT4 == destFormat ||
4795 WINED3DFMT_DXT5 == destFormat) {
4796 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4797 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4798 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4799 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4800 } if (destFormat != srcFormat) {
4801 FIXME("Updating mixed format compressed texture is not curretly support\n");
4803 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4804 glDescription->level,
4805 glDescription->glFormatInternal,
4810 IWineD3DSurface_GetData(pSourceSurface));
4813 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4818 glTexSubImage2D(glDescription->target
4819 ,glDescription->level
4824 ,glDescription->glFormat
4825 ,glDescription->glType
4826 ,IWineD3DSurface_GetData(pSourceSurface)
4830 checkGLcall("glTexSubImage2D");
4831 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4833 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4834 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4835 * surface bigger than it needs to be hmm.. */
4836 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4837 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4838 IWineD3DBaseTexture_Release(baseTexture);
4841 glDisable(textureDimensions); /* This needs to be managed better.... */
4847 /* Implementation details at http://developer.nvidia.com/attach/6494
4849 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4850 hmm.. no longer supported use
4851 OpenGL evaluators or tessellate surfaces within your application.
4854 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4855 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4857 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4858 FIXME("(%p) : Stub\n", This);
4863 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4864 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4866 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4867 FIXME("(%p) : Stub\n", This);
4871 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 TRACE("(%p) Handle(%d)\n", This, Handle);
4874 FIXME("(%p) : Stub\n", This);
4878 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4880 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4882 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4884 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4885 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4886 return WINED3DERR_INVALIDCALL;
4889 /* Just forward this to the DirectDraw blitting engine */
4890 memset(&BltFx, 0, sizeof(BltFx));
4891 BltFx.dwSize = sizeof(BltFx);
4892 BltFx.u5.dwFillColor = color;
4893 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4896 /* rendertarget and deptth stencil functions */
4897 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4900 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4901 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4902 return WINED3DERR_INVALIDCALL;
4905 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4906 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4907 /* Note inc ref on returned surface */
4908 if(*ppRenderTarget != NULL)
4909 IWineD3DSurface_AddRef(*ppRenderTarget);
4913 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4916 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4917 IWineD3DSwapChainImpl *Swapchain;
4920 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4922 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4923 if(hr != WINED3D_OK) {
4924 ERR("Can't get the swapchain\n");
4928 /* Make sure to release the swapchain */
4929 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4931 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4932 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4933 return WINED3DERR_INVALIDCALL;
4935 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4936 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4937 return WINED3DERR_INVALIDCALL;
4940 if(Swapchain->frontBuffer != Front) {
4941 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4943 if(Swapchain->frontBuffer)
4944 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4945 Swapchain->frontBuffer = Front;
4947 if(Swapchain->frontBuffer) {
4948 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4952 if(Back && !Swapchain->backBuffer) {
4953 /* We need memory for the back buffer array - only one back buffer this way */
4954 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4955 if(!Swapchain->backBuffer) {
4956 ERR("Out of memory\n");
4957 return E_OUTOFMEMORY;
4961 if(Swapchain->backBuffer[0] != Back) {
4962 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4964 if(!Swapchain->backBuffer[0]) {
4965 /* GL was told to draw to the front buffer at creation,
4968 glDrawBuffer(GL_BACK);
4969 checkGLcall("glDrawBuffer(GL_BACK)");
4970 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4971 Swapchain->presentParms.BackBufferCount = 1;
4973 /* That makes problems - disable for now */
4974 /* glDrawBuffer(GL_FRONT); */
4975 checkGLcall("glDrawBuffer(GL_FRONT)");
4976 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4977 Swapchain->presentParms.BackBufferCount = 0;
4981 if(Swapchain->backBuffer[0])
4982 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4983 Swapchain->backBuffer[0] = Back;
4985 if(Swapchain->backBuffer[0]) {
4986 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4988 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
4996 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 *ppZStencilSurface = This->depthStencilBuffer;
4999 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5001 if(*ppZStencilSurface != NULL) {
5002 /* Note inc ref on returned surface */
5003 IWineD3DSurface_AddRef(*ppZStencilSurface);
5008 static void bind_fbo(IWineD3DDevice *iface) {
5009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5012 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5013 checkGLcall("glGenFramebuffersEXT()");
5015 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5016 checkGLcall("glBindFramebuffer()");
5019 /* TODO: Handle stencil attachments */
5020 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5022 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5024 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5028 if (depth_stencil_impl) {
5029 GLenum texttarget, target;
5030 GLint old_binding = 0;
5032 IWineD3DSurface_PreLoad(depth_stencil);
5033 texttarget = depth_stencil_impl->glDescription.target;
5034 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5036 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5037 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5038 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5039 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5040 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5041 glBindTexture(target, old_binding);
5043 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5044 checkGLcall("glFramebufferTexture2DEXT()");
5046 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5047 checkGLcall("glFramebufferTexture2DEXT()");
5050 if (!This->render_offscreen) {
5051 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5052 checkGLcall("glBindFramebuffer()");
5056 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5058 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5060 if (idx >= GL_LIMITS(buffers)) {
5061 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5067 GLenum texttarget, target;
5068 GLint old_binding = 0;
5070 IWineD3DSurface_PreLoad(render_target);
5071 texttarget = rtimpl->glDescription.target;
5072 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5074 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5075 glBindTexture(target, rtimpl->glDescription.textureName);
5076 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5077 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5078 glBindTexture(target, old_binding);
5080 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5081 checkGLcall("glFramebufferTexture2DEXT()");
5083 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5085 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5086 checkGLcall("glFramebufferTexture2DEXT()");
5088 This->draw_buffers[idx] = GL_NONE;
5091 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5092 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5093 checkGLcall("glDrawBuffers()");
5096 if (!This->render_offscreen) {
5097 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5098 checkGLcall("glBindFramebuffer()");
5102 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5104 WINED3DVIEWPORT viewport;
5106 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5108 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5109 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5110 return WINED3DERR_INVALIDCALL;
5113 /* MSDN says that null disables the render target
5114 but a device must always be associated with a render target
5115 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5117 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5120 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5121 FIXME("Trying to set render target 0 to NULL\n");
5122 return WINED3DERR_INVALIDCALL;
5124 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5125 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);
5126 return WINED3DERR_INVALIDCALL;
5129 /* If we are trying to set what we already have, don't bother */
5130 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5131 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5134 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5135 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5136 This->render_targets[RenderTargetIndex] = pRenderTarget;
5138 /* Render target 0 is special */
5139 if(RenderTargetIndex == 0) {
5140 /* Finally, reset the viewport as the MSDN states. */
5141 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5142 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5145 viewport.MaxZ = 1.0f;
5146 viewport.MinZ = 0.0f;
5147 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5149 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5151 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5152 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5154 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5156 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5157 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 HRESULT hr = WINED3D_OK;
5165 IWineD3DSurface *tmp;
5167 TRACE("(%p) Swapping z-buffer\n",This);
5169 if (pNewZStencil == This->stencilBufferTarget) {
5170 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5172 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5173 * depending on the renter target implementation being used.
5174 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5175 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5176 * stencil buffer and incure an extra memory overhead
5177 ******************************************************/
5180 tmp = This->stencilBufferTarget;
5181 This->stencilBufferTarget = pNewZStencil;
5182 /* should we be calling the parent or the wined3d surface? */
5183 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5184 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5186 /** TODO: glEnable/glDisable on depth/stencil depending on
5187 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5188 **********************************************************/
5189 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5190 set_depth_stencil_fbo(iface, pNewZStencil);
5197 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5198 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5200 /* TODO: the use of Impl is deprecated. */
5201 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5203 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5205 /* some basic validation checks */
5206 if(This->cursorTexture) {
5208 glDeleteTextures(1, &This->cursorTexture);
5210 This->cursorTexture = 0;
5214 /* MSDN: Cursor must be A8R8G8B8 */
5215 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5216 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5217 return WINED3DERR_INVALIDCALL;
5220 /* MSDN: Cursor must be smaller than the display mode */
5221 if(pSur->currentDesc.Width > This->ddraw_width ||
5222 pSur->currentDesc.Height > This->ddraw_height) {
5223 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);
5224 return WINED3DERR_INVALIDCALL;
5227 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5228 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5229 * Texture and Blitting code to draw the cursor
5231 pSur->Flags |= SFLAG_FORCELOAD;
5232 IWineD3DSurface_PreLoad(pCursorBitmap);
5233 pSur->Flags &= ~SFLAG_FORCELOAD;
5234 /* Do not store the surface's pointer because the application may release
5235 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5236 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5238 This->cursorTexture = pSur->glDescription.textureName;
5239 This->cursorWidth = pSur->currentDesc.Width;
5240 This->cursorHeight = pSur->currentDesc.Height;
5241 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5244 This->xHotSpot = XHotSpot;
5245 This->yHotSpot = YHotSpot;
5249 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5251 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5253 This->xScreenSpace = XScreenSpace;
5254 This->yScreenSpace = YScreenSpace;
5260 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5262 BOOL oldVisible = This->bCursorVisible;
5263 TRACE("(%p) : visible(%d)\n", This, bShow);
5265 if(This->cursorTexture)
5266 This->bCursorVisible = bShow;
5271 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5273 TRACE("(%p) : state (%u)\n", This, This->state);
5274 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5275 switch (This->state) {
5278 case WINED3DERR_DEVICELOST:
5280 ResourceList *resourceList = This->resources;
5281 while (NULL != resourceList) {
5282 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5283 return WINED3DERR_DEVICENOTRESET;
5284 resourceList = resourceList->next;
5286 return WINED3DERR_DEVICELOST;
5288 case WINED3DERR_DRIVERINTERNALERROR:
5289 return WINED3DERR_DRIVERINTERNALERROR;
5293 return WINED3DERR_DRIVERINTERNALERROR;
5297 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5299 /** FIXME: Resource tracking needs to be done,
5300 * The closes we can do to this is set the priorities of all managed textures low
5301 * and then reset them.
5302 ***********************************************************/
5303 FIXME("(%p) : stub\n", This);
5307 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5308 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5310 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5311 if(surface->Flags & SFLAG_DIBSECTION) {
5312 /* Release the DC */
5313 SelectObject(surface->hDC, surface->dib.holdbitmap);
5314 DeleteDC(surface->hDC);
5315 /* Release the DIB section */
5316 DeleteObject(surface->dib.DIBsection);
5317 surface->dib.bitmap_data = NULL;
5318 surface->resource.allocatedMemory = NULL;
5319 surface->Flags &= ~SFLAG_DIBSECTION;
5321 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5322 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5323 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5324 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5325 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5327 surface->pow2Width = surface->pow2Height = 1;
5328 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5329 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5331 if(surface->glDescription.textureName) {
5333 glDeleteTextures(1, &surface->glDescription.textureName);
5335 surface->glDescription.textureName = 0;
5337 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5338 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5339 surface->Flags |= SFLAG_NONPOW2;
5341 surface->Flags &= ~SFLAG_NONPOW2;
5343 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5344 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5347 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5349 IWineD3DSwapChainImpl *swapchain;
5351 BOOL DisplayModeChanged = FALSE;
5352 WINED3DDISPLAYMODE mode;
5353 TRACE("(%p)\n", This);
5355 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5357 ERR("Failed to get the first implicit swapchain\n");
5361 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5362 * on an existing gl context, so there's no real need for recreation.
5364 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5366 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5368 TRACE("New params:\n");
5369 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5370 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5371 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5372 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5373 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5374 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5375 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5376 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5377 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5378 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5379 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5380 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5381 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5383 /* No special treatment of these parameters. Just store them */
5384 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5385 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5386 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5387 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5389 /* What to do about these? */
5390 if(pPresentationParameters->BackBufferCount != 0 &&
5391 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5392 ERR("Cannot change the back buffer count yet\n");
5394 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5395 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5396 ERR("Cannot change the back buffer format yet\n");
5398 if(pPresentationParameters->hDeviceWindow != NULL &&
5399 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5400 ERR("Cannot change the device window yet\n");
5402 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5403 ERR("What do do about a changed auto depth stencil parameter?\n");
5406 if(pPresentationParameters->Windowed) {
5407 mode.Width = swapchain->orig_width;
5408 mode.Height = swapchain->orig_height;
5409 mode.RefreshRate = 0;
5410 mode.Format = swapchain->presentParms.BackBufferFormat;
5412 mode.Width = pPresentationParameters->BackBufferWidth;
5413 mode.Height = pPresentationParameters->BackBufferHeight;
5414 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5415 mode.Format = swapchain->presentParms.BackBufferFormat;
5418 /* Should Width == 800 && Height == 0 set 800x600? */
5419 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5420 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5421 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5428 vp.Width = pPresentationParameters->BackBufferWidth;
5429 vp.Height = pPresentationParameters->BackBufferHeight;
5433 if(!pPresentationParameters->Windowed) {
5434 DisplayModeChanged = TRUE;
5436 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5437 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5439 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5440 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5441 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5444 /* Now set the new viewport */
5445 IWineD3DDevice_SetViewport(iface, &vp);
5448 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5449 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5450 DisplayModeChanged) {
5452 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5453 if(!pPresentationParameters->Windowed) {
5454 IWineD3DDevice_SetFullscreen(iface, TRUE);
5457 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5459 /* Switching out of fullscreen mode? First set the original res, then change the window */
5460 if(pPresentationParameters->Windowed) {
5461 IWineD3DDevice_SetFullscreen(iface, FALSE);
5463 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5466 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5470 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5472 /** FIXME: always true at the moment **/
5473 if(!bEnableDialogs) {
5474 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5480 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5482 TRACE("(%p) : pParameters %p\n", This, pParameters);
5484 *pParameters = This->createParms;
5488 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5489 IWineD3DSwapChain *swapchain;
5490 HRESULT hrc = WINED3D_OK;
5492 TRACE("Relaying to swapchain\n");
5494 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5495 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5496 IWineD3DSwapChain_Release(swapchain);
5501 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5502 IWineD3DSwapChain *swapchain;
5503 HRESULT hrc = WINED3D_OK;
5505 TRACE("Relaying to swapchain\n");
5507 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5508 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5509 IWineD3DSwapChain_Release(swapchain);
5515 /** ********************************************************
5516 * Notification functions
5517 ** ********************************************************/
5518 /** This function must be called in the release of a resource when ref == 0,
5519 * the contents of resource must still be correct,
5520 * any handels to other resource held by the caller must be closed
5521 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5522 *****************************************************/
5523 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5525 ResourceList* resourceList;
5527 TRACE("(%p) : resource %p\n", This, resource);
5529 EnterCriticalSection(&resourceStoreCriticalSection);
5531 /* add a new texture to the frot of the linked list */
5532 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5533 resourceList->resource = resource;
5535 /* Get the old head */
5536 resourceList->next = This->resources;
5538 This->resources = resourceList;
5539 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5542 LeaveCriticalSection(&resourceStoreCriticalSection);
5547 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5549 ResourceList* resourceList = NULL;
5550 ResourceList* previousResourceList = NULL;
5552 TRACE("(%p) : resource %p\n", This, resource);
5555 EnterCriticalSection(&resourceStoreCriticalSection);
5557 resourceList = This->resources;
5559 while (resourceList != NULL) {
5560 if(resourceList->resource == resource) break;
5561 previousResourceList = resourceList;
5562 resourceList = resourceList->next;
5565 if (resourceList == NULL) {
5566 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5568 LeaveCriticalSection(&resourceStoreCriticalSection);
5572 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5574 /* make sure we don't leave a hole in the list */
5575 if (previousResourceList != NULL) {
5576 previousResourceList->next = resourceList->next;
5578 This->resources = resourceList->next;
5582 LeaveCriticalSection(&resourceStoreCriticalSection);
5588 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5592 TRACE("(%p) : resource %p\n", This, resource);
5593 switch(IWineD3DResource_GetType(resource)){
5594 case WINED3DRTYPE_SURFACE:
5595 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5597 case WINED3DRTYPE_TEXTURE:
5598 case WINED3DRTYPE_CUBETEXTURE:
5599 case WINED3DRTYPE_VOLUMETEXTURE:
5600 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5601 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5602 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5603 This->stateBlock->textures[counter] = NULL;
5605 if (This->updateStateBlock != This->stateBlock ){
5606 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5607 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5608 This->updateStateBlock->textures[counter] = NULL;
5613 case WINED3DRTYPE_VOLUME:
5614 /* TODO: nothing really? */
5616 case WINED3DRTYPE_VERTEXBUFFER:
5617 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5620 TRACE("Cleaning up stream pointers\n");
5622 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5623 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5624 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5626 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5627 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5628 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5629 This->updateStateBlock->streamSource[streamNumber] = 0;
5630 /* Set changed flag? */
5633 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) */
5634 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5635 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5636 This->stateBlock->streamSource[streamNumber] = 0;
5639 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5640 else { /* This shouldn't happen */
5641 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5648 case WINED3DRTYPE_INDEXBUFFER:
5649 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5650 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5651 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5652 This->updateStateBlock->pIndexData = NULL;
5655 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5656 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5657 This->stateBlock->pIndexData = NULL;
5663 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5668 /* Remove the resoruce from the resourceStore */
5669 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5671 TRACE("Resource released\n");
5675 /**********************************************************
5676 * IWineD3DDevice VTbl follows
5677 **********************************************************/
5679 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5681 /*** IUnknown methods ***/
5682 IWineD3DDeviceImpl_QueryInterface,
5683 IWineD3DDeviceImpl_AddRef,
5684 IWineD3DDeviceImpl_Release,
5685 /*** IWineD3DDevice methods ***/
5686 IWineD3DDeviceImpl_GetParent,
5687 /*** Creation methods**/
5688 IWineD3DDeviceImpl_CreateVertexBuffer,
5689 IWineD3DDeviceImpl_CreateIndexBuffer,
5690 IWineD3DDeviceImpl_CreateStateBlock,
5691 IWineD3DDeviceImpl_CreateSurface,
5692 IWineD3DDeviceImpl_CreateTexture,
5693 IWineD3DDeviceImpl_CreateVolumeTexture,
5694 IWineD3DDeviceImpl_CreateVolume,
5695 IWineD3DDeviceImpl_CreateCubeTexture,
5696 IWineD3DDeviceImpl_CreateQuery,
5697 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5698 IWineD3DDeviceImpl_CreateVertexDeclaration,
5699 IWineD3DDeviceImpl_CreateVertexShader,
5700 IWineD3DDeviceImpl_CreatePixelShader,
5701 IWineD3DDeviceImpl_CreatePalette,
5702 /*** Odd functions **/
5703 IWineD3DDeviceImpl_Init3D,
5704 IWineD3DDeviceImpl_Uninit3D,
5705 IWineD3DDeviceImpl_SetFullscreen,
5706 IWineD3DDeviceImpl_EvictManagedResources,
5707 IWineD3DDeviceImpl_GetAvailableTextureMem,
5708 IWineD3DDeviceImpl_GetBackBuffer,
5709 IWineD3DDeviceImpl_GetCreationParameters,
5710 IWineD3DDeviceImpl_GetDeviceCaps,
5711 IWineD3DDeviceImpl_GetDirect3D,
5712 IWineD3DDeviceImpl_GetDisplayMode,
5713 IWineD3DDeviceImpl_SetDisplayMode,
5714 IWineD3DDeviceImpl_GetHWND,
5715 IWineD3DDeviceImpl_SetHWND,
5716 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5717 IWineD3DDeviceImpl_GetRasterStatus,
5718 IWineD3DDeviceImpl_GetSwapChain,
5719 IWineD3DDeviceImpl_Reset,
5720 IWineD3DDeviceImpl_SetDialogBoxMode,
5721 IWineD3DDeviceImpl_SetCursorProperties,
5722 IWineD3DDeviceImpl_SetCursorPosition,
5723 IWineD3DDeviceImpl_ShowCursor,
5724 IWineD3DDeviceImpl_TestCooperativeLevel,
5725 /*** Getters and setters **/
5726 IWineD3DDeviceImpl_SetClipPlane,
5727 IWineD3DDeviceImpl_GetClipPlane,
5728 IWineD3DDeviceImpl_SetClipStatus,
5729 IWineD3DDeviceImpl_GetClipStatus,
5730 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5731 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5732 IWineD3DDeviceImpl_SetDepthStencilSurface,
5733 IWineD3DDeviceImpl_GetDepthStencilSurface,
5734 IWineD3DDeviceImpl_SetFVF,
5735 IWineD3DDeviceImpl_GetFVF,
5736 IWineD3DDeviceImpl_SetGammaRamp,
5737 IWineD3DDeviceImpl_GetGammaRamp,
5738 IWineD3DDeviceImpl_SetIndices,
5739 IWineD3DDeviceImpl_GetIndices,
5740 IWineD3DDeviceImpl_SetBasevertexIndex,
5741 IWineD3DDeviceImpl_SetLight,
5742 IWineD3DDeviceImpl_GetLight,
5743 IWineD3DDeviceImpl_SetLightEnable,
5744 IWineD3DDeviceImpl_GetLightEnable,
5745 IWineD3DDeviceImpl_SetMaterial,
5746 IWineD3DDeviceImpl_GetMaterial,
5747 IWineD3DDeviceImpl_SetNPatchMode,
5748 IWineD3DDeviceImpl_GetNPatchMode,
5749 IWineD3DDeviceImpl_SetPaletteEntries,
5750 IWineD3DDeviceImpl_GetPaletteEntries,
5751 IWineD3DDeviceImpl_SetPixelShader,
5752 IWineD3DDeviceImpl_GetPixelShader,
5753 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5754 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5755 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5756 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5757 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5758 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5759 IWineD3DDeviceImpl_SetRenderState,
5760 IWineD3DDeviceImpl_GetRenderState,
5761 IWineD3DDeviceImpl_SetRenderTarget,
5762 IWineD3DDeviceImpl_GetRenderTarget,
5763 IWineD3DDeviceImpl_SetFrontBackBuffers,
5764 IWineD3DDeviceImpl_SetSamplerState,
5765 IWineD3DDeviceImpl_GetSamplerState,
5766 IWineD3DDeviceImpl_SetScissorRect,
5767 IWineD3DDeviceImpl_GetScissorRect,
5768 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5769 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5770 IWineD3DDeviceImpl_SetStreamSource,
5771 IWineD3DDeviceImpl_GetStreamSource,
5772 IWineD3DDeviceImpl_SetStreamSourceFreq,
5773 IWineD3DDeviceImpl_GetStreamSourceFreq,
5774 IWineD3DDeviceImpl_SetTexture,
5775 IWineD3DDeviceImpl_GetTexture,
5776 IWineD3DDeviceImpl_SetTextureStageState,
5777 IWineD3DDeviceImpl_GetTextureStageState,
5778 IWineD3DDeviceImpl_SetTransform,
5779 IWineD3DDeviceImpl_GetTransform,
5780 IWineD3DDeviceImpl_SetVertexDeclaration,
5781 IWineD3DDeviceImpl_GetVertexDeclaration,
5782 IWineD3DDeviceImpl_SetVertexShader,
5783 IWineD3DDeviceImpl_GetVertexShader,
5784 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5785 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5786 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5787 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5788 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5789 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5790 IWineD3DDeviceImpl_SetViewport,
5791 IWineD3DDeviceImpl_GetViewport,
5792 IWineD3DDeviceImpl_MultiplyTransform,
5793 IWineD3DDeviceImpl_ValidateDevice,
5794 IWineD3DDeviceImpl_ProcessVertices,
5795 /*** State block ***/
5796 IWineD3DDeviceImpl_BeginStateBlock,
5797 IWineD3DDeviceImpl_EndStateBlock,
5798 /*** Scene management ***/
5799 IWineD3DDeviceImpl_BeginScene,
5800 IWineD3DDeviceImpl_EndScene,
5801 IWineD3DDeviceImpl_Present,
5802 IWineD3DDeviceImpl_Clear,
5804 IWineD3DDeviceImpl_DrawPrimitive,
5805 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5806 IWineD3DDeviceImpl_DrawPrimitiveUP,
5807 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5808 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5809 IWineD3DDeviceImpl_DrawRectPatch,
5810 IWineD3DDeviceImpl_DrawTriPatch,
5811 IWineD3DDeviceImpl_DeletePatch,
5812 IWineD3DDeviceImpl_ColorFill,
5813 IWineD3DDeviceImpl_UpdateTexture,
5814 IWineD3DDeviceImpl_UpdateSurface,
5815 IWineD3DDeviceImpl_GetFrontBufferData,
5816 /*** object tracking ***/
5817 IWineD3DDeviceImpl_ResourceReleased
5821 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5822 WINED3DRS_ALPHABLENDENABLE ,
5823 WINED3DRS_ALPHAFUNC ,
5824 WINED3DRS_ALPHAREF ,
5825 WINED3DRS_ALPHATESTENABLE ,
5827 WINED3DRS_COLORWRITEENABLE ,
5828 WINED3DRS_DESTBLEND ,
5829 WINED3DRS_DITHERENABLE ,
5830 WINED3DRS_FILLMODE ,
5831 WINED3DRS_FOGDENSITY ,
5833 WINED3DRS_FOGSTART ,
5834 WINED3DRS_LASTPIXEL ,
5835 WINED3DRS_SHADEMODE ,
5836 WINED3DRS_SRCBLEND ,
5837 WINED3DRS_STENCILENABLE ,
5838 WINED3DRS_STENCILFAIL ,
5839 WINED3DRS_STENCILFUNC ,
5840 WINED3DRS_STENCILMASK ,
5841 WINED3DRS_STENCILPASS ,
5842 WINED3DRS_STENCILREF ,
5843 WINED3DRS_STENCILWRITEMASK ,
5844 WINED3DRS_STENCILZFAIL ,
5845 WINED3DRS_TEXTUREFACTOR ,
5856 WINED3DRS_ZWRITEENABLE
5859 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5860 WINED3DTSS_ADDRESSW ,
5861 WINED3DTSS_ALPHAARG0 ,
5862 WINED3DTSS_ALPHAARG1 ,
5863 WINED3DTSS_ALPHAARG2 ,
5864 WINED3DTSS_ALPHAOP ,
5865 WINED3DTSS_BUMPENVLOFFSET ,
5866 WINED3DTSS_BUMPENVLSCALE ,
5867 WINED3DTSS_BUMPENVMAT00 ,
5868 WINED3DTSS_BUMPENVMAT01 ,
5869 WINED3DTSS_BUMPENVMAT10 ,
5870 WINED3DTSS_BUMPENVMAT11 ,
5871 WINED3DTSS_COLORARG0 ,
5872 WINED3DTSS_COLORARG1 ,
5873 WINED3DTSS_COLORARG2 ,
5874 WINED3DTSS_COLOROP ,
5875 WINED3DTSS_RESULTARG ,
5876 WINED3DTSS_TEXCOORDINDEX ,
5877 WINED3DTSS_TEXTURETRANSFORMFLAGS
5880 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5881 WINED3DSAMP_ADDRESSU ,
5882 WINED3DSAMP_ADDRESSV ,
5883 WINED3DSAMP_ADDRESSW ,
5884 WINED3DSAMP_BORDERCOLOR ,
5885 WINED3DSAMP_MAGFILTER ,
5886 WINED3DSAMP_MINFILTER ,
5887 WINED3DSAMP_MIPFILTER ,
5888 WINED3DSAMP_MIPMAPLODBIAS ,
5889 WINED3DSAMP_MAXMIPLEVEL ,
5890 WINED3DSAMP_MAXANISOTROPY ,
5891 WINED3DSAMP_SRGBTEXTURE ,
5892 WINED3DSAMP_ELEMENTINDEX
5895 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5897 WINED3DRS_AMBIENTMATERIALSOURCE ,
5898 WINED3DRS_CLIPPING ,
5899 WINED3DRS_CLIPPLANEENABLE ,
5900 WINED3DRS_COLORVERTEX ,
5901 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5902 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5903 WINED3DRS_FOGDENSITY ,
5905 WINED3DRS_FOGSTART ,
5906 WINED3DRS_FOGTABLEMODE ,
5907 WINED3DRS_FOGVERTEXMODE ,
5908 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5909 WINED3DRS_LIGHTING ,
5910 WINED3DRS_LOCALVIEWER ,
5911 WINED3DRS_MULTISAMPLEANTIALIAS ,
5912 WINED3DRS_MULTISAMPLEMASK ,
5913 WINED3DRS_NORMALIZENORMALS ,
5914 WINED3DRS_PATCHEDGESTYLE ,
5915 WINED3DRS_POINTSCALE_A ,
5916 WINED3DRS_POINTSCALE_B ,
5917 WINED3DRS_POINTSCALE_C ,
5918 WINED3DRS_POINTSCALEENABLE ,
5919 WINED3DRS_POINTSIZE ,
5920 WINED3DRS_POINTSIZE_MAX ,
5921 WINED3DRS_POINTSIZE_MIN ,
5922 WINED3DRS_POINTSPRITEENABLE ,
5923 WINED3DRS_RANGEFOGENABLE ,
5924 WINED3DRS_SPECULARMATERIALSOURCE ,
5925 WINED3DRS_TWEENFACTOR ,
5926 WINED3DRS_VERTEXBLEND
5929 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5930 WINED3DTSS_TEXCOORDINDEX ,
5931 WINED3DTSS_TEXTURETRANSFORMFLAGS
5934 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5935 WINED3DSAMP_DMAPOFFSET
5938 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5939 DWORD rep = StateTable[state].representative;
5943 WineD3DContext *context;
5946 for(i = 0; i < This->numContexts; i++) {
5947 context = This->contexts[i];
5948 if(isStateDirty(context, rep)) continue;
5950 context->dirtyArray[context->numDirtyEntries++] = rep;
5953 context->isStateDirty[idx] |= (1 << shift);