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, SW_NORMAL);
1256 /*****************************************************************************
1257 * IWineD3DDeviceImpl_RestoreWindow
1259 * Helper function that restores a windows' properties when taking it out
1260 * of fullscreen mode
1263 * iface: Pointer to the IWineD3DDevice interface
1264 * window: Window to setup
1266 *****************************************************************************/
1267 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1271 * switch, do nothing
1273 if (!This->style && !This->exStyle) return;
1275 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1276 This, window, This->style, This->exStyle);
1278 SetWindowLongW(window, GWL_STYLE, This->style);
1279 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1281 /* Delete the old values */
1285 /* Inform the window about the update */
1286 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1287 0, 0, 0, 0, /* Pos, Size, ignored */
1288 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1291 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1292 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1294 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1295 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1300 HRESULT hr = WINED3D_OK;
1301 IUnknown *bufferParent;
1304 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1306 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1307 * does a device hold a reference to a swap chain giving them a lifetime of the device
1308 * or does the swap chain notify the device of its destruction.
1309 *******************************/
1311 /* Check the params */
1312 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1313 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1314 return WINED3DERR_INVALIDCALL;
1315 } else if (pPresentationParameters->BackBufferCount > 1) {
1316 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1319 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1321 /*********************
1322 * Lookup the window Handle and the relating X window handle
1323 ********************/
1325 /* Setup hwnd we are using, plus which display this equates to */
1326 object->win_handle = pPresentationParameters->hDeviceWindow;
1327 if (!object->win_handle) {
1328 object->win_handle = This->createParms.hFocusWindow;
1331 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1332 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1333 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1334 return WINED3DERR_NOTAVAILABLE;
1336 hDc = GetDC(object->win_handle);
1337 display = get_display(hDc);
1338 ReleaseDC(object->win_handle, hDc);
1339 TRACE("Using a display of %p %p\n", display, hDc);
1341 if (NULL == display || NULL == hDc) {
1342 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1343 return WINED3DERR_NOTAVAILABLE;
1346 if (object->win == 0) {
1347 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1348 return WINED3DERR_NOTAVAILABLE;
1351 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1352 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1353 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1355 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1356 * then the corresponding dimension of the client area of the hDeviceWindow
1357 * (or the focus window, if hDeviceWindow is NULL) is taken.
1358 **********************/
1360 if (pPresentationParameters->Windowed &&
1361 ((pPresentationParameters->BackBufferWidth == 0) ||
1362 (pPresentationParameters->BackBufferHeight == 0))) {
1365 GetClientRect(object->win_handle, &Rect);
1367 if (pPresentationParameters->BackBufferWidth == 0) {
1368 pPresentationParameters->BackBufferWidth = Rect.right;
1369 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1371 if (pPresentationParameters->BackBufferHeight == 0) {
1372 pPresentationParameters->BackBufferHeight = Rect.bottom;
1373 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1377 /* Put the correct figures in the presentation parameters */
1378 TRACE("Copying across presentation parameters\n");
1379 object->presentParms = *pPresentationParameters;
1381 TRACE("calling rendertarget CB\n");
1382 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1384 object->presentParms.BackBufferWidth,
1385 object->presentParms.BackBufferHeight,
1386 object->presentParms.BackBufferFormat,
1387 object->presentParms.MultiSampleType,
1388 object->presentParms.MultiSampleQuality,
1389 TRUE /* Lockable */,
1390 &object->frontBuffer,
1391 NULL /* pShared (always null)*/);
1392 if (object->frontBuffer != NULL) {
1393 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1395 ERR("Failed to create the front buffer\n");
1400 * Create an opengl context for the display visual
1401 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1402 * use different properties after that point in time. FIXME: How to handle when requested format
1403 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1404 * it chooses is identical to the one already being used!
1405 **********************************/
1407 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1409 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1412 if (!object->context) {
1413 ERR("Failed to create a new context\n");
1414 hr = WINED3DERR_NOTAVAILABLE;
1417 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1418 object->win_handle, object->context->glCtx, object->win);
1421 /*********************
1422 * Windowed / Fullscreen
1423 *******************/
1426 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1427 * so we should really check to see if there is a fullscreen swapchain already
1428 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1429 **************************************/
1431 if (!pPresentationParameters->Windowed) {
1438 /* Get info on the current display setup */
1440 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1443 /* Change the display settings */
1444 memset(&devmode, 0, sizeof(DEVMODEW));
1445 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1446 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1447 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1448 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1449 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1450 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1452 /* For GetDisplayMode */
1453 This->ddraw_width = devmode.dmPelsWidth;
1454 This->ddraw_height = devmode.dmPelsHeight;
1455 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1457 IWineD3DDevice_SetFullscreen(iface, TRUE);
1459 /* And finally clip mouse to our screen */
1460 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1461 ClipCursor(&clip_rc);
1464 /*********************
1465 * Create the back, front and stencil buffers
1466 *******************/
1467 if(object->presentParms.BackBufferCount > 0) {
1470 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1471 if(!object->backBuffer) {
1472 ERR("Out of memory\n");
1477 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1478 TRACE("calling rendertarget CB\n");
1479 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1481 object->presentParms.BackBufferWidth,
1482 object->presentParms.BackBufferHeight,
1483 object->presentParms.BackBufferFormat,
1484 object->presentParms.MultiSampleType,
1485 object->presentParms.MultiSampleQuality,
1486 TRUE /* Lockable */,
1487 &object->backBuffer[i],
1488 NULL /* pShared (always null)*/);
1489 if(hr == WINED3D_OK && object->backBuffer[i]) {
1490 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1492 ERR("Cannot create new back buffer\n");
1496 glDrawBuffer(GL_BACK);
1497 checkGLcall("glDrawBuffer(GL_BACK)");
1501 object->backBuffer = NULL;
1503 /* Single buffering - draw to front buffer */
1505 glDrawBuffer(GL_FRONT);
1506 checkGLcall("glDrawBuffer(GL_FRONT)");
1510 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1511 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1512 TRACE("Creating depth stencil buffer\n");
1513 if (This->depthStencilBuffer == NULL ) {
1514 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1516 object->presentParms.BackBufferWidth,
1517 object->presentParms.BackBufferHeight,
1518 object->presentParms.AutoDepthStencilFormat,
1519 object->presentParms.MultiSampleType,
1520 object->presentParms.MultiSampleQuality,
1521 FALSE /* FIXME: Discard */,
1522 &This->depthStencilBuffer,
1523 NULL /* pShared (always null)*/ );
1524 if (This->depthStencilBuffer != NULL)
1525 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1528 /** TODO: A check on width, height and multisample types
1529 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1530 ****************************/
1531 object->wantsDepthStencilBuffer = TRUE;
1533 object->wantsDepthStencilBuffer = FALSE;
1536 TRACE("Created swapchain %p\n", object);
1537 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1541 if (object->backBuffer) {
1543 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1544 if(object->backBuffer[i]) {
1545 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1546 IUnknown_Release(bufferParent); /* once for the get parent */
1547 if (IUnknown_Release(bufferParent) > 0) {
1548 FIXME("(%p) Something's still holding the back buffer\n",This);
1552 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1553 object->backBuffer = NULL;
1555 if(object->context) {
1556 DestroyContext(This, object->context);
1558 if(object->frontBuffer) {
1559 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1560 IUnknown_Release(bufferParent); /* once for the get parent */
1561 if (IUnknown_Release(bufferParent) > 0) {
1562 FIXME("(%p) Something's still holding the front buffer\n",This);
1565 if(object) HeapFree(GetProcessHeap(), 0, object);
1569 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1570 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1572 TRACE("(%p)\n", This);
1574 return This->NumberOfSwapChains;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1579 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1581 if(iSwapChain < This->NumberOfSwapChains) {
1582 *pSwapChain = This->swapchains[iSwapChain];
1583 IWineD3DSwapChain_AddRef(*pSwapChain);
1584 TRACE("(%p) returning %p\n", This, *pSwapChain);
1587 TRACE("Swapchain out of range\n");
1589 return WINED3DERR_INVALIDCALL;
1594 * Vertex Declaration
1596 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1597 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1599 IWineD3DVertexDeclarationImpl *object = NULL;
1600 HRESULT hr = WINED3D_OK;
1602 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1603 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1605 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1608 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1613 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1614 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1616 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1617 HRESULT hr = WINED3D_OK;
1618 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1619 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1621 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1623 if (vertex_declaration) {
1624 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1627 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1629 if (WINED3D_OK != hr) {
1630 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1631 IWineD3DVertexShader_Release(*ppVertexShader);
1632 return WINED3DERR_INVALIDCALL;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1641 HRESULT hr = WINED3D_OK;
1643 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1644 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1645 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1646 if (WINED3D_OK == hr) {
1647 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1649 WARN("(%p) : Failed to create pixel shader\n", This);
1655 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1657 IWineD3DPaletteImpl *object;
1659 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1661 /* Create the new object */
1662 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1664 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1665 return E_OUTOFMEMORY;
1668 object->lpVtbl = &IWineD3DPalette_Vtbl;
1670 object->Flags = Flags;
1671 object->parent = Parent;
1672 object->wineD3DDevice = This;
1673 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1675 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1678 HeapFree( GetProcessHeap(), 0, object);
1679 return E_OUTOFMEMORY;
1682 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1684 IWineD3DPalette_Release((IWineD3DPalette *) object);
1688 *Palette = (IWineD3DPalette *) object;
1693 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1695 IWineD3DSwapChainImpl *swapchain;
1698 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1699 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1701 /* TODO: Test if OpenGL is compiled in and loaded */
1703 /* Initialize the texture unit mapping to a 1:1 mapping */
1704 for(state = 0; state < MAX_SAMPLERS; state++) {
1705 This->texUnitMap[state] = state;
1707 This->oneToOneTexUnitMap = TRUE;
1709 /* Setup the implicit swapchain */
1710 TRACE("Creating implicit swapchain\n");
1711 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1712 WARN("Failed to create implicit swapchain\n");
1713 return WINED3DERR_INVALIDCALL;
1716 This->NumberOfSwapChains = 1;
1717 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1718 if(!This->swapchains) {
1719 ERR("Out of memory!\n");
1720 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1721 return E_OUTOFMEMORY;
1723 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1725 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1727 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1728 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1729 This->render_targets[0] = swapchain->backBuffer[0];
1730 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1733 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1734 This->render_targets[0] = swapchain->frontBuffer;
1735 This->lastActiveRenderTarget = swapchain->frontBuffer;
1737 IWineD3DSurface_AddRef(This->render_targets[0]);
1738 This->activeContext = swapchain->context;
1740 /* Depth Stencil support */
1741 This->stencilBufferTarget = This->depthStencilBuffer;
1742 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1743 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1745 if (NULL != This->stencilBufferTarget) {
1746 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1749 /* Set up some starting GL setup */
1752 * Initialize openGL extension related variables
1753 * with Default values
1756 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1757 /* Setup all the devices defaults */
1758 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1760 IWineD3DImpl_CheckGraphicsMemory();
1763 /* Initialize our list of GLSL programs */
1764 list_init(&This->glsl_shader_progs);
1766 { /* Set a default viewport */
1770 vp.Width = pPresentationParameters->BackBufferWidth;
1771 vp.Height = pPresentationParameters->BackBufferHeight;
1774 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1777 /* Initialize the current view state */
1778 This->view_ident = 1;
1779 This->contexts[0]->last_was_rhw = 0;
1780 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1781 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1782 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1785 /* Clear the screen */
1786 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1788 This->d3d_initialized = TRUE;
1792 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1796 TRACE("(%p)\n", This);
1798 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1800 /* Delete the pbuffer context if there is any */
1801 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1803 /* Delete the mouse cursor texture */
1804 if(This->cursorTexture) {
1806 glDeleteTextures(1, &This->cursorTexture);
1808 This->cursorTexture = 0;
1811 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1812 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1815 /* Release the buffers (with sanity checks)*/
1816 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1817 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1818 if(This->depthStencilBuffer != This->stencilBufferTarget)
1819 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1821 This->stencilBufferTarget = NULL;
1823 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1824 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1825 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1827 TRACE("Setting rendertarget to NULL\n");
1828 This->render_targets[0] = NULL;
1830 if (This->depthStencilBuffer) {
1831 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1832 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1834 This->depthStencilBuffer = NULL;
1837 for(i=0; i < This->NumberOfSwapChains; i++) {
1838 TRACE("Releasing the implicit swapchain %d\n", i);
1839 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1840 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1844 HeapFree(GetProcessHeap(), 0, This->swapchains);
1845 This->swapchains = NULL;
1846 This->NumberOfSwapChains = 0;
1848 This->d3d_initialized = FALSE;
1852 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1854 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1856 /* Setup the window for fullscreen mode */
1857 if(fullscreen && !This->ddraw_fullscreen) {
1858 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1859 } else if(!fullscreen && This->ddraw_fullscreen) {
1860 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1863 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1864 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1865 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1868 This->ddraw_fullscreen = fullscreen;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1875 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1878 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1880 /* Resize the screen even without a window:
1881 * The app could have unset it with SetCooperativeLevel, but not called
1882 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1883 * but we don't have any hwnd
1886 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1887 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1888 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1889 devmode.dmPelsWidth = pMode->Width;
1890 devmode.dmPelsHeight = pMode->Height;
1892 devmode.dmDisplayFrequency = pMode->RefreshRate;
1893 if (pMode->RefreshRate != 0) {
1894 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1897 /* Only change the mode if necessary */
1898 if( (This->ddraw_width == pMode->Width) &&
1899 (This->ddraw_height == pMode->Height) &&
1900 (This->ddraw_format == pMode->Format) &&
1901 (pMode->RefreshRate == 0) ) {
1905 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1906 if (ret != DISP_CHANGE_SUCCESSFUL) {
1907 if(devmode.dmDisplayFrequency != 0) {
1908 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1909 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1910 devmode.dmDisplayFrequency = 0;
1911 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1913 if(ret != DISP_CHANGE_SUCCESSFUL) {
1914 return DDERR_INVALIDMODE;
1918 /* Store the new values */
1919 This->ddraw_width = pMode->Width;
1920 This->ddraw_height = pMode->Height;
1921 This->ddraw_format = pMode->Format;
1923 /* Only do this with a window of course */
1924 if(This->ddraw_window)
1925 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1927 /* And finally clip mouse to our screen */
1928 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1929 ClipCursor(&clip_rc);
1934 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1936 *ppD3D= This->wineD3D;
1937 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1938 IWineD3D_AddRef(*ppD3D);
1942 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1943 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1944 * into the video ram as possible and seeing how many fit
1945 * you can also get the correct initial value from nvidia and ATI's driver via X
1946 * texture memory is video memory + AGP memory
1947 *******************/
1948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1949 static BOOL showfixmes = TRUE;
1951 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1952 (wined3d_settings.emulated_textureram/(1024*1024)),
1953 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1956 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1957 (wined3d_settings.emulated_textureram/(1024*1024)),
1958 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1959 /* return simulated texture memory left */
1960 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1968 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1971 /* Update the current state block */
1972 This->updateStateBlock->changed.fvf = TRUE;
1973 This->updateStateBlock->set.fvf = TRUE;
1975 if(This->updateStateBlock->fvf == fvf) {
1976 TRACE("Application is setting the old fvf over, nothing to do\n");
1980 This->updateStateBlock->fvf = fvf;
1981 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1987 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1989 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1990 *pfvf = This->stateBlock->fvf;
1995 * Get / Set Stream Source
1997 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1999 IWineD3DVertexBuffer *oldSrc;
2001 if (StreamNumber >= MAX_STREAMS) {
2002 WARN("Stream out of range %d\n", StreamNumber);
2003 return WINED3DERR_INVALIDCALL;
2006 oldSrc = This->stateBlock->streamSource[StreamNumber];
2007 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2009 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2010 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2012 if(oldSrc == pStreamData &&
2013 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2014 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2015 TRACE("Application is setting the old values over, nothing to do\n");
2019 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2021 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2022 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2025 /* Handle recording of state blocks */
2026 if (This->isRecordingState) {
2027 TRACE("Recording... not performing anything\n");
2031 /* Need to do a getParent and pass the reffs up */
2032 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2033 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2034 so for now, just count internally */
2035 if (pStreamData != NULL) {
2036 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2037 InterlockedIncrement(&vbImpl->bindCount);
2039 if (oldSrc != NULL) {
2040 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2048 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2051 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2052 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2054 if (StreamNumber >= MAX_STREAMS) {
2055 WARN("Stream out of range %d\n", StreamNumber);
2056 return WINED3DERR_INVALIDCALL;
2058 *pStream = This->stateBlock->streamSource[StreamNumber];
2059 *pStride = This->stateBlock->streamStride[StreamNumber];
2061 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2064 if (*pStream != NULL) {
2065 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2070 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2072 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2073 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2075 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2076 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2078 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2079 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2080 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2082 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2083 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2090 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2094 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2096 TRACE("(%p) : returning %d\n", This, *Divider);
2102 * Get / Set & Multiply Transform
2104 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2107 /* Most of this routine, comments included copied from ddraw tree initially: */
2108 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2110 /* Handle recording of state blocks */
2111 if (This->isRecordingState) {
2112 TRACE("Recording... not performing anything\n");
2113 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2114 This->updateStateBlock->set.transform[d3dts] = TRUE;
2115 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2120 * If the new matrix is the same as the current one,
2121 * we cut off any further processing. this seems to be a reasonable
2122 * optimization because as was noticed, some apps (warcraft3 for example)
2123 * tend towards setting the same matrix repeatedly for some reason.
2125 * From here on we assume that the new matrix is different, wherever it matters.
2127 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2128 TRACE("The app is setting the same matrix over again\n");
2131 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2135 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2136 where ViewMat = Camera space, WorldMat = world space.
2138 In OpenGL, camera and world space is combined into GL_MODELVIEW
2139 matrix. The Projection matrix stay projection matrix.
2142 /* Capture the times we can just ignore the change for now */
2143 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2144 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2145 /* Handled by the state manager */
2148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2152 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2155 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2159 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2160 WINED3DMATRIX *mat = NULL;
2163 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2164 * below means it will be recorded in a state block change, but it
2165 * works regardless where it is recorded.
2166 * If this is found to be wrong, change to StateBlock.
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2171 if (State < HIGHEST_TRANSFORMSTATE)
2173 mat = &This->updateStateBlock->transforms[State];
2175 FIXME("Unhandled transform state!!\n");
2178 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2180 /* Apply change via set transform - will reapply to eg. lights this way */
2181 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2187 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2188 you can reference any indexes you want as long as that number max are enabled at any
2189 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2190 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2191 but when recording, just build a chain pretty much of commands to be replayed. */
2193 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2195 PLIGHTINFOEL *object = NULL;
2196 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2200 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2202 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2206 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2207 return WINED3DERR_INVALIDCALL;
2210 switch(pLight->Type) {
2211 case WINED3DLIGHT_POINT:
2212 case WINED3DLIGHT_SPOT:
2213 case WINED3DLIGHT_PARALLELPOINT:
2214 case WINED3DLIGHT_GLSPOT:
2215 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2218 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2219 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2220 return WINED3DERR_INVALIDCALL;
2224 case WINED3DLIGHT_DIRECTIONAL:
2225 /* Ignores attenuation */
2229 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2230 return WINED3DERR_INVALIDCALL;
2233 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2234 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2235 if(object->OriginalIndex == Index) break;
2240 TRACE("Adding new light\n");
2241 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2243 ERR("Out of memory error when allocating a light\n");
2244 return E_OUTOFMEMORY;
2246 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2247 object->glIndex = -1;
2248 object->OriginalIndex = Index;
2249 object->changed = TRUE;
2252 /* Initialize the object */
2253 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2254 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2255 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2256 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2257 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2258 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2259 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2261 /* Save away the information */
2262 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2264 switch (pLight->Type) {
2265 case WINED3DLIGHT_POINT:
2267 object->lightPosn[0] = pLight->Position.x;
2268 object->lightPosn[1] = pLight->Position.y;
2269 object->lightPosn[2] = pLight->Position.z;
2270 object->lightPosn[3] = 1.0f;
2271 object->cutoff = 180.0f;
2275 case WINED3DLIGHT_DIRECTIONAL:
2277 object->lightPosn[0] = -pLight->Direction.x;
2278 object->lightPosn[1] = -pLight->Direction.y;
2279 object->lightPosn[2] = -pLight->Direction.z;
2280 object->lightPosn[3] = 0.0;
2281 object->exponent = 0.0f;
2282 object->cutoff = 180.0f;
2285 case WINED3DLIGHT_SPOT:
2287 object->lightPosn[0] = pLight->Position.x;
2288 object->lightPosn[1] = pLight->Position.y;
2289 object->lightPosn[2] = pLight->Position.z;
2290 object->lightPosn[3] = 1.0;
2293 object->lightDirn[0] = pLight->Direction.x;
2294 object->lightDirn[1] = pLight->Direction.y;
2295 object->lightDirn[2] = pLight->Direction.z;
2296 object->lightDirn[3] = 1.0;
2299 * opengl-ish and d3d-ish spot lights use too different models for the
2300 * light "intensity" as a function of the angle towards the main light direction,
2301 * so we only can approximate very roughly.
2302 * however spot lights are rather rarely used in games (if ever used at all).
2303 * furthermore if still used, probably nobody pays attention to such details.
2305 if (pLight->Falloff == 0) {
2308 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2310 if (rho < 0.0001) rho = 0.0001f;
2311 object->exponent = -0.3/log(cos(rho/2));
2312 if (object->exponent > 128.0) {
2313 object->exponent = 128.0;
2315 object->cutoff = pLight->Phi*90/M_PI;
2321 FIXME("Unrecognized light type %d\n", pLight->Type);
2324 /* Update the live definitions if the light is currently assigned a glIndex */
2325 if (object->glIndex != -1 && !This->isRecordingState) {
2326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2332 PLIGHTINFOEL *lightInfo = NULL;
2333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2336 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2338 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2339 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2340 if(lightInfo->OriginalIndex == Index) break;
2344 if (lightInfo == NULL) {
2345 TRACE("Light information requested but light not defined\n");
2346 return WINED3DERR_INVALIDCALL;
2349 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2354 * Get / Set Light Enable
2355 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2358 PLIGHTINFOEL *lightInfo = NULL;
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2362 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2364 /* Tests show true = 128...not clear why */
2365 Enable = Enable? 128: 0;
2367 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2368 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2369 if(lightInfo->OriginalIndex == Index) break;
2372 TRACE("Found light: %p\n", lightInfo);
2374 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2375 if (lightInfo == NULL) {
2377 TRACE("Light enabled requested but light not defined, so defining one!\n");
2378 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2380 /* Search for it again! Should be fairly quick as near head of list */
2381 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2382 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2383 if(lightInfo->OriginalIndex == Index) break;
2386 if (lightInfo == NULL) {
2387 FIXME("Adding default lights has failed dismally\n");
2388 return WINED3DERR_INVALIDCALL;
2392 lightInfo->enabledChanged = TRUE;
2394 if(lightInfo->glIndex != -1) {
2395 if(!This->isRecordingState) {
2396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2399 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2400 lightInfo->glIndex = -1;
2402 TRACE("Light already disabled, nothing to do\n");
2405 if (lightInfo->glIndex != -1) {
2407 TRACE("Nothing to do as light was enabled\n");
2410 /* Find a free gl light */
2411 for(i = 0; i < This->maxConcurrentLights; i++) {
2412 if(This->stateBlock->activeLights[i] == NULL) {
2413 This->stateBlock->activeLights[i] = lightInfo;
2414 lightInfo->glIndex = i;
2418 if(lightInfo->glIndex == -1) {
2419 ERR("Too many concurrently active lights\n");
2420 return WINED3DERR_INVALIDCALL;
2423 /* i == lightInfo->glIndex */
2424 if(!This->isRecordingState) {
2425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2433 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2435 PLIGHTINFOEL *lightInfo = NULL;
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2439 TRACE("(%p) : for idx(%d)\n", This, Index);
2441 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2442 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2443 if(lightInfo->OriginalIndex == Index) break;
2447 if (lightInfo == NULL) {
2448 TRACE("Light enabled state requested but light not defined\n");
2449 return WINED3DERR_INVALIDCALL;
2451 /* true is 128 according to SetLightEnable */
2452 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2457 * Get / Set Clip Planes
2459 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2463 /* Validate Index */
2464 if (Index >= GL_LIMITS(clipplanes)) {
2465 TRACE("Application has requested clipplane this device doesn't support\n");
2466 return WINED3DERR_INVALIDCALL;
2469 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2470 This->updateStateBlock->set.clipplane[Index] = TRUE;
2471 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2472 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2473 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2474 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2476 /* Handle recording of state blocks */
2477 if (This->isRecordingState) {
2478 TRACE("Recording... not performing anything\n");
2486 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2487 glMatrixMode(GL_MODELVIEW);
2489 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2491 TRACE("Clipplane [%f,%f,%f,%f]\n",
2492 This->updateStateBlock->clipplane[Index][0],
2493 This->updateStateBlock->clipplane[Index][1],
2494 This->updateStateBlock->clipplane[Index][2],
2495 This->updateStateBlock->clipplane[Index][3]);
2496 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2497 checkGLcall("glClipPlane");
2505 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2507 TRACE("(%p) : for idx %d\n", This, Index);
2509 /* Validate Index */
2510 if (Index >= GL_LIMITS(clipplanes)) {
2511 TRACE("Application has requested clipplane this device doesn't support\n");
2512 return WINED3DERR_INVALIDCALL;
2515 pPlane[0] = This->stateBlock->clipplane[Index][0];
2516 pPlane[1] = This->stateBlock->clipplane[Index][1];
2517 pPlane[2] = This->stateBlock->clipplane[Index][2];
2518 pPlane[3] = This->stateBlock->clipplane[Index][3];
2523 * Get / Set Clip Plane Status
2524 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2526 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 FIXME("(%p) : stub\n", This);
2529 if (NULL == pClipStatus) {
2530 return WINED3DERR_INVALIDCALL;
2532 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2533 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2537 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 FIXME("(%p) : stub\n", This);
2540 if (NULL == pClipStatus) {
2541 return WINED3DERR_INVALIDCALL;
2543 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2544 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2549 * Get / Set Material
2551 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 This->updateStateBlock->changed.material = TRUE;
2555 This->updateStateBlock->set.material = TRUE;
2556 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2558 /* Handle recording of state blocks */
2559 if (This->isRecordingState) {
2560 TRACE("Recording... not performing anything\n");
2565 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2566 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2567 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2568 pMaterial->Ambient.b, pMaterial->Ambient.a);
2569 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2570 pMaterial->Specular.b, pMaterial->Specular.a);
2571 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2572 pMaterial->Emissive.b, pMaterial->Emissive.a);
2573 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2575 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2576 checkGLcall("glMaterialfv(GL_AMBIENT)");
2577 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2578 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2580 /* Only change material color if specular is enabled, otherwise it is set to black */
2581 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2582 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2583 checkGLcall("glMaterialfv(GL_SPECULAR");
2585 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2586 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2587 checkGLcall("glMaterialfv(GL_SPECULAR");
2589 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2590 checkGLcall("glMaterialfv(GL_EMISSION)");
2591 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2592 checkGLcall("glMaterialf(GL_SHININESS");
2598 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2601 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2602 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2603 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2604 pMaterial->Ambient.b, pMaterial->Ambient.a);
2605 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2606 pMaterial->Specular.b, pMaterial->Specular.a);
2607 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2608 pMaterial->Emissive.b, pMaterial->Emissive.a);
2609 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2617 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2618 UINT BaseVertexIndex) {
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2620 IWineD3DIndexBuffer *oldIdxs;
2621 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2623 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2624 oldIdxs = This->updateStateBlock->pIndexData;
2626 This->updateStateBlock->changed.indices = TRUE;
2627 This->updateStateBlock->set.indices = TRUE;
2628 This->updateStateBlock->pIndexData = pIndexData;
2629 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2631 /* Handle recording of state blocks */
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2637 /* The base vertex index affects the stream sources, while
2638 * The index buffer is a seperate index buffer state
2640 if(BaseVertexIndex != oldBaseIndex) {
2641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2643 if(oldIdxs != pIndexData) {
2644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 *ppIndexData = This->stateBlock->pIndexData;
2654 /* up ref count on ppindexdata */
2656 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2657 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2658 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2660 TRACE("(%p) No index data set\n", This);
2662 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2667 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 TRACE("(%p)->(%d)\n", This, BaseIndex);
2672 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2673 TRACE("Application is setting the old value over, nothing to do\n");
2677 This->updateStateBlock->baseVertexIndex = BaseIndex;
2679 if (This->isRecordingState) {
2680 TRACE("Recording... not performing anything\n");
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2688 * Get / Set Viewports
2690 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 TRACE("(%p)\n", This);
2694 This->updateStateBlock->changed.viewport = TRUE;
2695 This->updateStateBlock->set.viewport = TRUE;
2696 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2698 /* Handle recording of state blocks */
2699 if (This->isRecordingState) {
2700 TRACE("Recording... not performing anything\n");
2704 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2705 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2712 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 TRACE("(%p)\n", This);
2715 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2720 * Get / Set Render States
2721 * TODO: Verify against dx9 definitions
2723 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 DWORD oldValue = This->stateBlock->renderState[State];
2728 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2730 This->updateStateBlock->changed.renderState[State] = TRUE;
2731 This->updateStateBlock->set.renderState[State] = TRUE;
2732 This->updateStateBlock->renderState[State] = Value;
2734 /* Handle recording of state blocks */
2735 if (This->isRecordingState) {
2736 TRACE("Recording... not performing anything\n");
2740 /* Compared here and not before the assignment to allow proper stateblock recording */
2741 if(Value == oldValue) {
2742 TRACE("Application is setting the old value over, nothing to do\n");
2744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2750 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2753 *pValue = This->stateBlock->renderState[State];
2758 * Get / Set Sampler States
2759 * TODO: Verify against dx9 definitions
2762 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2767 * SetSampler is designed to allow for more than the standard up to 8 textures
2768 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2769 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2771 * http://developer.nvidia.com/object/General_FAQ.html#t6
2773 * There are two new settings for GForce
2775 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2776 * and the texture one:
2777 * GL_MAX_TEXTURE_COORDS_ARB.
2778 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2781 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2782 debug_d3dsamplerstate(Type), Type, Value);
2783 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2784 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2785 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2787 /* Handle recording of state blocks */
2788 if (This->isRecordingState) {
2789 TRACE("Recording... not performing anything\n");
2793 if(oldValue == Value) {
2794 TRACE("Application is setting the old value over, nothing to do\n");
2798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2803 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 *Value = This->stateBlock->samplerState[Sampler][Type];
2806 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 This->updateStateBlock->set.scissorRect = TRUE;
2815 This->updateStateBlock->changed.scissorRect = TRUE;
2816 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2817 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2820 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2822 if(This->isRecordingState) {
2823 TRACE("Recording... not performing anything\n");
2827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2832 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2836 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2840 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2842 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2844 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2846 This->updateStateBlock->vertexDecl = pDecl;
2847 This->updateStateBlock->changed.vertexDecl = TRUE;
2848 This->updateStateBlock->set.vertexDecl = TRUE;
2850 if (This->isRecordingState) {
2851 TRACE("Recording... not performing anything\n");
2853 } else if(pDecl == oldDecl) {
2854 /* Checked after the assignment to allow proper stateblock recording */
2855 TRACE("Application is setting the old declaration over, nothing to do\n");
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2863 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2868 *ppDecl = This->stateBlock->vertexDecl;
2869 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2873 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2877 This->updateStateBlock->vertexShader = pShader;
2878 This->updateStateBlock->changed.vertexShader = TRUE;
2879 This->updateStateBlock->set.vertexShader = TRUE;
2881 if (This->isRecordingState) {
2882 TRACE("Recording... not performing anything\n");
2884 } else if(oldShader == pShader) {
2885 /* Checked here to allow proper stateblock recording */
2886 TRACE("App is setting the old shader over, nothing to do\n");
2890 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2892 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2897 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 if (NULL == ppShader) {
2901 return WINED3DERR_INVALIDCALL;
2903 *ppShader = This->stateBlock->vertexShader;
2904 if( NULL != *ppShader)
2905 IWineD3DVertexShader_AddRef(*ppShader);
2907 TRACE("(%p) : returning %p\n", This, *ppShader);
2911 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2912 IWineD3DDevice *iface,
2914 CONST BOOL *srcData,
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 int i, cnt = min(count, MAX_CONST_B - start);
2920 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2921 iface, srcData, start, count);
2923 if (srcData == NULL || cnt < 0)
2924 return WINED3DERR_INVALIDCALL;
2926 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2927 for (i = 0; i < cnt; i++)
2928 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2930 for (i = start; i < cnt + start; ++i) {
2931 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2932 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2941 IWineD3DDevice *iface,
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 int cnt = min(count, MAX_CONST_B - start);
2949 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2950 iface, dstData, start, count);
2952 if (dstData == NULL || cnt < 0)
2953 return WINED3DERR_INVALIDCALL;
2955 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2959 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2960 IWineD3DDevice *iface,
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 int i, cnt = min(count, MAX_CONST_I - start);
2968 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2969 iface, srcData, start, count);
2971 if (srcData == NULL || cnt < 0)
2972 return WINED3DERR_INVALIDCALL;
2974 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2975 for (i = 0; i < cnt; i++)
2976 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2977 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2979 for (i = start; i < cnt + start; ++i) {
2980 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2981 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2989 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2990 IWineD3DDevice *iface,
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 int cnt = min(count, MAX_CONST_I - start);
2998 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2999 iface, dstData, start, count);
3001 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3002 return WINED3DERR_INVALIDCALL;
3004 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3009 IWineD3DDevice *iface,
3011 CONST float *srcData,
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3018 iface, srcData, start, count);
3020 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3021 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3022 return WINED3DERR_INVALIDCALL;
3024 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3026 for (i = 0; i < count; i++)
3027 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3028 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3031 for (i = start; i < count + start; ++i) {
3032 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3033 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3035 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3036 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3038 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3047 IWineD3DDevice *iface,
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3055 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3056 iface, dstData, start, count);
3058 if (dstData == NULL || cnt < 0)
3059 return WINED3DERR_INVALIDCALL;
3061 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3065 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3067 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3072 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3074 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3075 * it is never called.
3078 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3079 * that would be really messy and require shader recompilation
3080 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3081 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3082 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3083 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3085 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3086 if(This->oneToOneTexUnitMap) {
3087 TRACE("Not touching 1:1 map\n");
3090 TRACE("Restoring 1:1 texture unit mapping\n");
3091 /* Restore a 1:1 mapping */
3092 for(i = 0; i < MAX_SAMPLERS; i++) {
3093 if(This->texUnitMap[i] != i) {
3094 This->texUnitMap[i] = i;
3095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3096 markTextureStagesDirty(This, i);
3099 This->oneToOneTexUnitMap = TRUE;
3102 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3103 * First, see if we can succeed at all
3106 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3107 if(This->stateBlock->textures[i] == NULL) tex++;
3110 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3111 FIXME("Too many bound textures to support the combiner settings\n");
3115 /* Now work out the mapping */
3117 This->oneToOneTexUnitMap = FALSE;
3118 WARN("Non 1:1 mapping UNTESTED!\n");
3119 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3120 /* Skip NULL textures */
3121 if (!This->stateBlock->textures[i]) {
3122 /* Map to -1, so the check below doesn't fail if a non-NULL
3123 * texture is set on this stage */
3124 TRACE("Mapping texture stage %d to -1\n", i);
3125 This->texUnitMap[i] = -1;
3130 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3131 if(This->texUnitMap[i] != tex) {
3132 This->texUnitMap[i] = tex;
3133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3134 markTextureStagesDirty(This, i);
3142 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3145 This->updateStateBlock->pixelShader = pShader;
3146 This->updateStateBlock->changed.pixelShader = TRUE;
3147 This->updateStateBlock->set.pixelShader = TRUE;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3159 if(pShader == oldShader) {
3160 TRACE("App is setting the old pixel shader over, nothing to do\n");
3164 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3167 /* Rebuild the texture unit mapping if nvrc's are supported */
3168 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3169 IWineD3DDeviceImpl_FindTexUnitMap(This);
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 if (NULL == ppShader) {
3179 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3180 return WINED3DERR_INVALIDCALL;
3183 *ppShader = This->stateBlock->pixelShader;
3184 if (NULL != *ppShader) {
3185 IWineD3DPixelShader_AddRef(*ppShader);
3187 TRACE("(%p) : returning %p\n", This, *ppShader);
3191 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3192 IWineD3DDevice *iface,
3194 CONST BOOL *srcData,
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 int i, cnt = min(count, MAX_CONST_B - start);
3200 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3201 iface, srcData, start, count);
3203 if (srcData == NULL || cnt < 0)
3204 return WINED3DERR_INVALIDCALL;
3206 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3207 for (i = 0; i < cnt; i++)
3208 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3210 for (i = start; i < cnt + start; ++i) {
3211 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3212 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3220 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3221 IWineD3DDevice *iface,
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 int cnt = min(count, MAX_CONST_B - start);
3229 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3230 iface, dstData, start, count);
3232 if (dstData == NULL || cnt < 0)
3233 return WINED3DERR_INVALIDCALL;
3235 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3239 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3240 IWineD3DDevice *iface,
3245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3246 int i, cnt = min(count, MAX_CONST_I - start);
3248 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3249 iface, srcData, start, count);
3251 if (srcData == NULL || cnt < 0)
3252 return WINED3DERR_INVALIDCALL;
3254 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3255 for (i = 0; i < cnt; i++)
3256 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3257 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3259 for (i = start; i < cnt + start; ++i) {
3260 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3261 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3269 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3270 IWineD3DDevice *iface,
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 int cnt = min(count, MAX_CONST_I - start);
3278 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3279 iface, dstData, start, count);
3281 if (dstData == NULL || cnt < 0)
3282 return WINED3DERR_INVALIDCALL;
3284 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3289 IWineD3DDevice *iface,
3291 CONST float *srcData,
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3298 iface, srcData, start, count);
3300 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3301 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3302 return WINED3DERR_INVALIDCALL;
3304 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3306 for (i = 0; i < count; i++)
3307 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3308 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3311 for (i = start; i < count + start; ++i) {
3312 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3313 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3315 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3316 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3318 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3326 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3327 IWineD3DDevice *iface,
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3335 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3336 iface, dstData, start, count);
3338 if (dstData == NULL || cnt < 0)
3339 return WINED3DERR_INVALIDCALL;
3341 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3345 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3347 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3348 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3350 DWORD DestFVF = dest->fvf;
3352 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3356 if (SrcFVF & WINED3DFVF_NORMAL) {
3357 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3360 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3361 ERR("Source has no position mask\n");
3362 return WINED3DERR_INVALIDCALL;
3365 /* We might access VBOs from this code, so hold the lock */
3368 if (dest->resource.allocatedMemory == NULL) {
3369 /* This may happen if we do direct locking into a vbo. Unlikely,
3370 * but theoretically possible(ddraw processvertices test)
3372 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3373 if(!dest->resource.allocatedMemory) {
3375 ERR("Out of memory\n");
3376 return E_OUTOFMEMORY;
3380 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3381 checkGLcall("glBindBufferARB");
3382 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3384 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3386 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3387 checkGLcall("glUnmapBufferARB");
3391 /* Get a pointer into the destination vbo(create one if none exists) and
3392 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3394 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3399 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3400 if(!dest_conv_addr) {
3401 ERR("Out of memory\n");
3402 /* Continue without storing converted vertices */
3404 dest_conv = dest_conv_addr;
3408 * a) WINED3DRS_CLIPPING is enabled
3409 * b) WINED3DVOP_CLIP is passed
3411 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3412 static BOOL warned = FALSE;
3414 * The clipping code is not quite correct. Some things need
3415 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3416 * so disable clipping for now.
3417 * (The graphics in Half-Life are broken, and my processvertices
3418 * test crashes with IDirect3DDevice3)
3424 FIXME("Clipping is broken and disabled for now\n");
3426 } else doClip = FALSE;
3427 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3429 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3432 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3433 WINED3DTS_PROJECTION,
3435 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3436 WINED3DTS_WORLDMATRIX(0),
3439 TRACE("View mat:\n");
3440 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);
3441 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);
3442 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);
3443 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);
3445 TRACE("Proj mat:\n");
3446 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);
3447 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);
3448 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);
3449 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);
3451 TRACE("World mat:\n");
3452 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);
3453 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);
3454 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);
3455 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);
3457 /* Get the viewport */
3458 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3459 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3460 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3462 multiply_matrix(&mat,&view_mat,&world_mat);
3463 multiply_matrix(&mat,&proj_mat,&mat);
3465 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3467 for (i = 0; i < dwCount; i+= 1) {
3468 unsigned int tex_index;
3470 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3471 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3472 /* The position first */
3474 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3476 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3478 /* Multiplication with world, view and projection matrix */
3479 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);
3480 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);
3481 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);
3482 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);
3484 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3486 /* WARNING: The following things are taken from d3d7 and were not yet checked
3487 * against d3d8 or d3d9!
3490 /* Clipping conditions: From
3491 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3493 * A vertex is clipped if it does not match the following requirements
3497 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3499 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3500 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3505 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3506 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3509 /* "Normal" viewport transformation (not clipped)
3510 * 1) The values are divided by rhw
3511 * 2) The y axis is negative, so multiply it with -1
3512 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3513 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3514 * 4) Multiply x with Width/2 and add Width/2
3515 * 5) The same for the height
3516 * 6) Add the viewpoint X and Y to the 2D coordinates and
3517 * The minimum Z value to z
3518 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3520 * Well, basically it's simply a linear transformation into viewport
3532 z *= vp.MaxZ - vp.MinZ;
3534 x += vp.Width / 2 + vp.X;
3535 y += vp.Height / 2 + vp.Y;
3540 /* That vertex got clipped
3541 * Contrary to OpenGL it is not dropped completely, it just
3542 * undergoes a different calculation.
3544 TRACE("Vertex got clipped\n");
3551 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3552 * outside of the main vertex buffer memory. That needs some more
3557 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3560 ( (float *) dest_ptr)[0] = x;
3561 ( (float *) dest_ptr)[1] = y;
3562 ( (float *) dest_ptr)[2] = z;
3563 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3565 dest_ptr += 3 * sizeof(float);
3567 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3568 dest_ptr += sizeof(float);
3573 ( (float *) dest_conv)[0] = x * w;
3574 ( (float *) dest_conv)[1] = y * w;
3575 ( (float *) dest_conv)[2] = z * w;
3576 ( (float *) dest_conv)[3] = w;
3578 dest_conv += 3 * sizeof(float);
3580 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3581 dest_conv += sizeof(float);
3585 if (DestFVF & WINED3DFVF_PSIZE) {
3586 dest_ptr += sizeof(DWORD);
3587 if(dest_conv) dest_conv += sizeof(DWORD);
3589 if (DestFVF & WINED3DFVF_NORMAL) {
3591 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3592 /* AFAIK this should go into the lighting information */
3593 FIXME("Didn't expect the destination to have a normal\n");
3594 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3596 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3600 if (DestFVF & WINED3DFVF_DIFFUSE) {
3602 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3604 static BOOL warned = FALSE;
3607 ERR("No diffuse color in source, but destination has one\n");
3611 *( (DWORD *) dest_ptr) = 0xffffffff;
3612 dest_ptr += sizeof(DWORD);
3615 *( (DWORD *) dest_conv) = 0xffffffff;
3616 dest_conv += sizeof(DWORD);
3620 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3622 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3623 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3624 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3625 dest_conv += sizeof(DWORD);
3630 if (DestFVF & WINED3DFVF_SPECULAR) {
3631 /* What's the color value in the feedback buffer? */
3633 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3635 static BOOL warned = FALSE;
3638 ERR("No specular color in source, but destination has one\n");
3642 *( (DWORD *) dest_ptr) = 0xFF000000;
3643 dest_ptr += sizeof(DWORD);
3646 *( (DWORD *) dest_conv) = 0xFF000000;
3647 dest_conv += sizeof(DWORD);
3651 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3653 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3654 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3655 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3656 dest_conv += sizeof(DWORD);
3661 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3663 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3664 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3666 ERR("No source texture, but destination requests one\n");
3667 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3668 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3671 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3673 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3680 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3681 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3682 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3683 dwCount * get_flexible_vertex_size(DestFVF),
3685 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3686 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3693 #undef copy_and_next
3695 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3697 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3698 WineDirect3DVertexStridedData strided;
3699 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3702 WARN("NULL source vertex buffer\n");
3703 return WINED3DERR_INVALIDCALL;
3705 /* We don't need the source vbo because this buffer is only used as
3706 * a source for ProcessVertices. Avoid wasting resources by converting the
3707 * buffer and loading the VBO
3710 TRACE("Releasing the source vbo, it won't be needed\n");
3712 if(!SrcImpl->resource.allocatedMemory) {
3713 /* Rescue the data from the buffer */
3715 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3716 if(!SrcImpl->resource.allocatedMemory) {
3717 ERR("Out of memory\n");
3718 return E_OUTOFMEMORY;
3722 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3723 checkGLcall("glBindBufferARB");
3725 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3727 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3730 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3731 checkGLcall("glUnmapBufferARB");
3736 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3737 checkGLcall("glBindBufferARB");
3738 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3739 checkGLcall("glDeleteBuffersARB");
3745 memset(&strided, 0, sizeof(strided));
3746 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3748 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3752 * Get / Set Texture Stage States
3753 * TODO: Verify against dx9 definitions
3755 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3759 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3761 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3763 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3764 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3765 This->updateStateBlock->textureState[Stage][Type] = Value;
3767 if (This->isRecordingState) {
3768 TRACE("Recording... not performing anything\n");
3772 /* Checked after the assignments to allow proper stateblock recording */
3773 if(oldValue == Value) {
3774 TRACE("App is setting the old value over, nothing to do\n");
3778 if(Stage > This->stateBlock->lowest_disabled_stage &&
3779 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3780 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3781 * Changes in other states are important on disabled stages too
3786 if(Type == WINED3DTSS_COLOROP) {
3789 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3790 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3791 * they have to be disabled
3793 * The current stage is dirtified below.
3795 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3796 TRACE("Additionally dirtifying stage %d\n", i);
3797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3799 This->stateBlock->lowest_disabled_stage = Stage;
3800 TRACE("New lowest disabled: %d\n", Stage);
3801 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3802 /* Previously disabled stage enabled. Stages above it may need enabling
3803 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3804 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3806 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3809 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3810 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3813 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3814 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3816 This->stateBlock->lowest_disabled_stage = i;
3817 TRACE("New lowest disabled: %d\n", i);
3819 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3820 /* TODO: Built a stage -> texture unit mapping for register combiners */
3824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3826 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3827 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3828 * will call FindTexUnitMap too.
3830 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3831 IWineD3DDeviceImpl_FindTexUnitMap(This);
3836 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3838 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3839 *pValue = This->updateStateBlock->textureState[Stage][Type];
3846 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3849 IWineD3DBaseTexture *oldTexture;
3851 oldTexture = This->updateStateBlock->textures[Stage];
3852 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3854 #if 0 /* TODO: check so vertex textures */
3855 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3856 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3861 if(pTexture != NULL) {
3862 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3864 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3865 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3866 return WINED3DERR_INVALIDCALL;
3868 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3871 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3872 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3874 This->updateStateBlock->set.textures[Stage] = TRUE;
3875 This->updateStateBlock->changed.textures[Stage] = TRUE;
3876 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3877 This->updateStateBlock->textures[Stage] = pTexture;
3879 /* Handle recording of state blocks */
3880 if (This->isRecordingState) {
3881 TRACE("Recording... not performing anything\n");
3885 if(oldTexture == pTexture) {
3886 TRACE("App is setting the same texture again, nothing to do\n");
3890 /** NOTE: MSDN says that setTexture increases the reference count,
3891 * and the the application nust set the texture back to null (or have a leaky application),
3892 * This means we should pass the refcount up to the parent
3893 *******************************/
3894 if (NULL != This->updateStateBlock->textures[Stage]) {
3895 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3896 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3898 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3899 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3900 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3901 * so the COLOROP and ALPHAOP have to be dirtified.
3903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3906 if(bindCount == 1) {
3907 new->baseTexture.sampler = Stage;
3909 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3913 if (NULL != oldTexture) {
3914 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3915 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3917 IWineD3DBaseTexture_Release(oldTexture);
3918 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3923 if(bindCount && old->baseTexture.sampler == Stage) {
3925 /* Have to do a search for the other sampler(s) where the texture is bound to
3926 * Shouldn't happen as long as apps bind a texture only to one stage
3928 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3929 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3930 if(This->updateStateBlock->textures[i] == oldTexture) {
3931 old->baseTexture.sampler = i;
3938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3940 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3941 * pixel shader is used
3943 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3944 IWineD3DDeviceImpl_FindTexUnitMap(This);
3950 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3952 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3954 *ppTexture=This->stateBlock->textures[Stage];
3956 IWineD3DBaseTexture_AddRef(*ppTexture);
3964 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3965 IWineD3DSurface **ppBackBuffer) {
3966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3967 IWineD3DSwapChain *swapChain;
3970 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3972 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3973 if (hr == WINED3D_OK) {
3974 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3975 IWineD3DSwapChain_Release(swapChain);
3977 *ppBackBuffer = NULL;
3982 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3984 WARN("(%p) : stub, calling idirect3d for now\n", This);
3985 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3988 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3990 IWineD3DSwapChain *swapChain;
3993 if(iSwapChain > 0) {
3994 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3995 if (hr == WINED3D_OK) {
3996 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3997 IWineD3DSwapChain_Release(swapChain);
3999 FIXME("(%p) Error getting display mode\n", This);
4002 /* Don't read the real display mode,
4003 but return the stored mode instead. X11 can't change the color
4004 depth, and some apps are pretty angry if they SetDisplayMode from
4005 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4007 Also don't relay to the swapchain because with ddraw it's possible
4008 that there isn't a swapchain at all */
4009 pMode->Width = This->ddraw_width;
4010 pMode->Height = This->ddraw_height;
4011 pMode->Format = This->ddraw_format;
4012 pMode->RefreshRate = 0;
4019 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 TRACE("(%p)->(%p)\n", This, hWnd);
4023 if(This->ddraw_fullscreen) {
4024 if(This->ddraw_window && This->ddraw_window != hWnd) {
4025 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4027 if(hWnd && This->ddraw_window != hWnd) {
4028 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4032 This->ddraw_window = hWnd;
4036 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4038 TRACE("(%p)->(%p)\n", This, hWnd);
4040 *hWnd = This->ddraw_window;
4045 * Stateblock related functions
4048 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4050 IWineD3DStateBlockImpl *object;
4051 HRESULT temp_result;
4054 TRACE("(%p)\n", This);
4056 if (This->isRecordingState) {
4057 return WINED3DERR_INVALIDCALL;
4060 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4061 if (NULL == object ) {
4062 FIXME("(%p)Error allocating memory for stateblock\n", This);
4063 return E_OUTOFMEMORY;
4065 TRACE("(%p) created object %p\n", This, object);
4066 object->wineD3DDevice= This;
4067 /** FIXME: object->parent = parent; **/
4068 object->parent = NULL;
4069 object->blockType = WINED3DSBT_ALL;
4071 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4073 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4074 list_init(&object->lightMap[i]);
4077 temp_result = allocate_shader_constants(object);
4078 if (WINED3D_OK != temp_result)
4081 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4082 This->updateStateBlock = object;
4083 This->isRecordingState = TRUE;
4085 TRACE("(%p) recording stateblock %p\n",This , object);
4089 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4092 if (!This->isRecordingState) {
4093 FIXME("(%p) not recording! returning error\n", This);
4094 *ppStateBlock = NULL;
4095 return WINED3DERR_INVALIDCALL;
4098 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4099 This->isRecordingState = FALSE;
4100 This->updateStateBlock = This->stateBlock;
4101 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4102 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4103 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4108 * Scene related functions
4110 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4111 /* At the moment we have no need for any functionality at the beginning
4113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4114 TRACE("(%p)\n", This);
4117 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4118 return WINED3DERR_INVALIDCALL;
4120 This->inScene = TRUE;
4124 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4126 TRACE("(%p)\n", This);
4128 if(!This->inScene) {
4129 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4130 return WINED3DERR_INVALIDCALL;
4134 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4136 checkGLcall("glFlush");
4139 This->inScene = FALSE;
4143 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4144 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4145 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4147 IWineD3DSwapChain *swapChain = NULL;
4149 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4151 TRACE("(%p) Presenting the frame\n", This);
4153 for(i = 0 ; i < swapchains ; i ++) {
4155 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4156 TRACE("presentinng chain %d, %p\n", i, swapChain);
4157 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4158 IWineD3DSwapChain_Release(swapChain);
4164 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4165 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4168 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4169 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4170 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4171 GLbitfield glMask = 0;
4173 CONST WINED3DRECT* curRect;
4175 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4176 Count, pRects, Flags, Z, Stencil);
4181 glEnable(GL_SCISSOR_TEST);
4182 checkGLcall("glEnable GL_SCISSOR_TEST");
4183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4185 glDisable(GL_SCISSOR_TEST);
4186 checkGLcall("glEnable GL_SCISSOR_TEST");
4188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4190 if (Count > 0 && pRects) {
4196 /* Only set the values up once, as they are not changing */
4197 if (Flags & WINED3DCLEAR_STENCIL) {
4198 glClearStencil(Stencil);
4199 checkGLcall("glClearStencil");
4200 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4201 glStencilMask(0xFFFFFFFF);
4204 if (Flags & WINED3DCLEAR_ZBUFFER) {
4205 glDepthMask(GL_TRUE);
4207 checkGLcall("glClearDepth");
4208 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4212 if (Flags & WINED3DCLEAR_TARGET) {
4213 TRACE("Clearing screen with glClear to color %x\n", Color);
4214 glClearColor(D3DCOLOR_R(Color),
4218 checkGLcall("glClearColor");
4220 /* Clear ALL colors! */
4221 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4222 glMask = glMask | GL_COLOR_BUFFER_BIT;
4225 /* Now process each rect in turn */
4226 for (i = 0; i < Count || i == 0; i++) {
4229 /* Note gl uses lower left, width/height */
4230 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4231 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4232 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4233 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4234 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4235 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4236 checkGLcall("glScissor");
4239 /* Clear the selected rectangle (or full screen) */
4241 checkGLcall("glClear");
4243 /* Step to the next rectangle */
4244 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4247 /* Restore the old values (why..?) */
4248 if (Flags & WINED3DCLEAR_STENCIL) {
4249 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4251 if (Flags & WINED3DCLEAR_TARGET) {
4252 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4253 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4254 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4255 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4260 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4261 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4263 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4271 UINT PrimitiveCount) {
4273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4274 This->stateBlock->streamIsUP = FALSE;
4276 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4277 debug_d3dprimitivetype(PrimitiveType),
4278 StartVertex, PrimitiveCount);
4280 if(This->stateBlock->loadBaseVertexIndex != 0) {
4281 This->stateBlock->loadBaseVertexIndex = 0;
4282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4284 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4285 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4286 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4290 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4291 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4292 WINED3DPRIMITIVETYPE PrimitiveType,
4293 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4297 IWineD3DIndexBuffer *pIB;
4298 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4301 pIB = This->stateBlock->pIndexData;
4302 This->stateBlock->streamIsUP = FALSE;
4303 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4305 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4306 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4307 minIndex, NumVertices, startIndex, primCount);
4309 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4310 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4316 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4317 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4321 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4322 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4327 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4328 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4329 UINT VertexStreamZeroStride) {
4330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4332 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4333 debug_d3dprimitivetype(PrimitiveType),
4334 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4336 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4337 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4338 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4339 This->stateBlock->streamIsUP = TRUE;
4340 This->stateBlock->loadBaseVertexIndex = 0;
4342 /* TODO: Only mark dirty if drawing from a different UP address */
4343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4345 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4346 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4348 /* MSDN specifies stream zero settings must be set to NULL */
4349 This->stateBlock->streamStride[0] = 0;
4350 This->stateBlock->streamSource[0] = NULL;
4352 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4353 * the new stream sources or use UP drawing again
4358 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4359 UINT MinVertexIndex, UINT NumVertices,
4360 UINT PrimitiveCount, CONST void* pIndexData,
4361 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4362 UINT VertexStreamZeroStride) {
4364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4366 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4367 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4368 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4369 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4371 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4377 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4378 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4379 This->stateBlock->streamIsUP = TRUE;
4380 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4382 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4383 This->stateBlock->baseVertexIndex = 0;
4384 This->stateBlock->loadBaseVertexIndex = 0;
4385 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4386 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4389 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4391 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4392 This->stateBlock->streamSource[0] = NULL;
4393 This->stateBlock->streamStride[0] = 0;
4394 This->stateBlock->pIndexData = NULL;
4395 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4396 * SetStreamSource to specify a vertex buffer
4402 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4405 /* Mark the state dirty until we have nicer tracking
4406 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4411 This->stateBlock->baseVertexIndex = 0;
4412 This->up_strided = DrawPrimStrideData;
4413 This->stateBlock->streamIsUP = TRUE;
4414 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4415 This->up_strided = NULL;
4418 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4419 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4421 HRESULT hr = WINED3D_OK;
4422 WINED3DRESOURCETYPE sourceType;
4423 WINED3DRESOURCETYPE destinationType;
4426 /* TODO: think about moving the code into IWineD3DBaseTexture */
4428 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4430 /* verify that the source and destination textures aren't NULL */
4431 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4432 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4433 This, pSourceTexture, pDestinationTexture);
4434 hr = WINED3DERR_INVALIDCALL;
4437 if (pSourceTexture == pDestinationTexture) {
4438 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4439 This, pSourceTexture, pDestinationTexture);
4440 hr = WINED3DERR_INVALIDCALL;
4442 /* Verify that the source and destination textures are the same type */
4443 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4444 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4446 if (sourceType != destinationType) {
4447 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4449 hr = WINED3DERR_INVALIDCALL;
4452 /* check that both textures have the identical numbers of levels */
4453 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4454 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4455 hr = WINED3DERR_INVALIDCALL;
4458 if (WINED3D_OK == hr) {
4460 /* Make sure that the destination texture is loaded */
4461 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4463 /* Update every surface level of the texture */
4464 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4466 switch (sourceType) {
4467 case WINED3DRTYPE_TEXTURE:
4469 IWineD3DSurface *srcSurface;
4470 IWineD3DSurface *destSurface;
4472 for (i = 0 ; i < levels ; ++i) {
4473 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4474 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4475 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4476 IWineD3DSurface_Release(srcSurface);
4477 IWineD3DSurface_Release(destSurface);
4478 if (WINED3D_OK != hr) {
4479 WARN("(%p) : Call to update surface failed\n", This);
4485 case WINED3DRTYPE_CUBETEXTURE:
4487 IWineD3DSurface *srcSurface;
4488 IWineD3DSurface *destSurface;
4489 WINED3DCUBEMAP_FACES faceType;
4491 for (i = 0 ; i < levels ; ++i) {
4492 /* Update each cube face */
4493 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4494 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4495 if (WINED3D_OK != hr) {
4496 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4498 TRACE("Got srcSurface %p\n", srcSurface);
4500 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4501 if (WINED3D_OK != hr) {
4502 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4504 TRACE("Got desrSurface %p\n", destSurface);
4506 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4507 IWineD3DSurface_Release(srcSurface);
4508 IWineD3DSurface_Release(destSurface);
4509 if (WINED3D_OK != hr) {
4510 WARN("(%p) : Call to update surface failed\n", This);
4517 #if 0 /* TODO: Add support for volume textures */
4518 case WINED3DRTYPE_VOLUMETEXTURE:
4520 IWineD3DVolume srcVolume = NULL;
4521 IWineD3DSurface destVolume = NULL;
4523 for (i = 0 ; i < levels ; ++i) {
4524 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4525 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4526 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4527 IWineD3DVolume_Release(srcSurface);
4528 IWineD3DVolume_Release(destSurface);
4529 if (WINED3D_OK != hr) {
4530 WARN("(%p) : Call to update volume failed\n", This);
4538 FIXME("(%p) : Unsupported source and destination type\n", This);
4539 hr = WINED3DERR_INVALIDCALL;
4546 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4547 IWineD3DSwapChain *swapChain;
4549 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4550 if(hr == WINED3D_OK) {
4551 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4552 IWineD3DSwapChain_Release(swapChain);
4557 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 /* return a sensible default */
4561 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4562 FIXME("(%p) : stub\n", This);
4566 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4570 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4571 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4572 return WINED3DERR_INVALIDCALL;
4574 for (j = 0; j < 256; ++j) {
4575 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4576 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4577 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4578 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4580 TRACE("(%p) : returning\n", This);
4584 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4587 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4588 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4589 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4590 return WINED3DERR_INVALIDCALL;
4592 for (j = 0; j < 256; ++j) {
4593 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4594 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4595 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4596 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4598 TRACE("(%p) : returning\n", This);
4602 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4604 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4605 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4606 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4607 return WINED3DERR_INVALIDCALL;
4609 /*TODO: stateblocks */
4610 This->currentPalette = PaletteNumber;
4611 TRACE("(%p) : returning\n", This);
4615 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4617 if (PaletteNumber == NULL) {
4618 WARN("(%p) : returning Invalid Call\n", This);
4619 return WINED3DERR_INVALIDCALL;
4621 /*TODO: stateblocks */
4622 *PaletteNumber = This->currentPalette;
4623 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4627 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 static BOOL showFixmes = TRUE;
4631 FIXME("(%p) : stub\n", This);
4635 This->softwareVertexProcessing = bSoftware;
4640 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 static BOOL showFixmes = TRUE;
4644 FIXME("(%p) : stub\n", This);
4647 return This->softwareVertexProcessing;
4651 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4653 IWineD3DSwapChain *swapChain;
4656 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4658 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4659 if(hr == WINED3D_OK){
4660 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4661 IWineD3DSwapChain_Release(swapChain);
4663 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4669 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 static BOOL showfixmes = TRUE;
4672 if(nSegments != 0.0f) {
4674 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4681 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 static BOOL showfixmes = TRUE;
4685 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4691 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4693 /** TODO: remove casts to IWineD3DSurfaceImpl
4694 * NOTE: move code to surface to accomplish this
4695 ****************************************/
4696 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4697 int srcWidth, srcHeight;
4698 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4699 WINED3DFORMAT destFormat, srcFormat;
4701 int srcLeft, destLeft, destTop;
4702 WINED3DPOOL srcPool, destPool;
4704 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4705 glDescriptor *glDescription = NULL;
4707 WINED3DSURFACE_DESC winedesc;
4709 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4710 memset(&winedesc, 0, sizeof(winedesc));
4711 winedesc.Width = &srcSurfaceWidth;
4712 winedesc.Height = &srcSurfaceHeight;
4713 winedesc.Pool = &srcPool;
4714 winedesc.Format = &srcFormat;
4716 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4718 winedesc.Width = &destSurfaceWidth;
4719 winedesc.Height = &destSurfaceHeight;
4720 winedesc.Pool = &destPool;
4721 winedesc.Format = &destFormat;
4722 winedesc.Size = &destSize;
4724 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4726 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4727 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4728 return WINED3DERR_INVALIDCALL;
4731 if (destFormat == WINED3DFMT_UNKNOWN) {
4732 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4733 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4735 /* Get the update surface description */
4736 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4740 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4741 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4742 checkGLcall("glActiveTextureARB");
4745 /* Make sure the surface is loaded and up to date */
4746 IWineD3DSurface_PreLoad(pDestinationSurface);
4748 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4750 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4751 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4752 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4753 srcLeft = pSourceRect ? pSourceRect->left : 0;
4754 destLeft = pDestPoint ? pDestPoint->x : 0;
4755 destTop = pDestPoint ? pDestPoint->y : 0;
4758 /* This function doesn't support compressed textures
4759 the pitch is just bytesPerPixel * width */
4760 if(srcWidth != srcSurfaceWidth || srcLeft ){
4761 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4762 offset += srcLeft * pSrcSurface->bytesPerPixel;
4763 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4765 /* TODO DXT formats */
4767 if(pSourceRect != NULL && pSourceRect->top != 0){
4768 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4770 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4772 ,glDescription->level
4777 ,glDescription->glFormat
4778 ,glDescription->glType
4779 ,IWineD3DSurface_GetData(pSourceSurface)
4783 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4785 /* need to lock the surface to get the data */
4786 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4789 /* TODO: Cube and volume support */
4791 /* not a whole row so we have to do it a line at a time */
4794 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4795 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4797 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4799 glTexSubImage2D(glDescription->target
4800 ,glDescription->level
4805 ,glDescription->glFormat
4806 ,glDescription->glType
4807 ,data /* could be quicker using */
4812 } else { /* Full width, so just write out the whole texture */
4814 if (WINED3DFMT_DXT1 == destFormat ||
4815 WINED3DFMT_DXT2 == destFormat ||
4816 WINED3DFMT_DXT3 == destFormat ||
4817 WINED3DFMT_DXT4 == destFormat ||
4818 WINED3DFMT_DXT5 == destFormat) {
4819 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4820 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4821 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4822 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4823 } if (destFormat != srcFormat) {
4824 FIXME("Updating mixed format compressed texture is not curretly support\n");
4826 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4827 glDescription->level,
4828 glDescription->glFormatInternal,
4833 IWineD3DSurface_GetData(pSourceSurface));
4836 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4841 glTexSubImage2D(glDescription->target
4842 ,glDescription->level
4847 ,glDescription->glFormat
4848 ,glDescription->glType
4849 ,IWineD3DSurface_GetData(pSourceSurface)
4853 checkGLcall("glTexSubImage2D");
4857 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4863 /* Implementation details at http://developer.nvidia.com/attach/6494
4865 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4866 hmm.. no longer supported use
4867 OpenGL evaluators or tessellate surfaces within your application.
4870 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4871 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4874 FIXME("(%p) : Stub\n", This);
4879 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4880 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4883 FIXME("(%p) : Stub\n", This);
4887 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4889 TRACE("(%p) Handle(%d)\n", This, Handle);
4890 FIXME("(%p) : Stub\n", This);
4894 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4896 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4898 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4900 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4901 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4902 return WINED3DERR_INVALIDCALL;
4905 /* Just forward this to the DirectDraw blitting engine */
4906 memset(&BltFx, 0, sizeof(BltFx));
4907 BltFx.dwSize = sizeof(BltFx);
4908 BltFx.u5.dwFillColor = color;
4909 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4912 /* rendertarget and deptth stencil functions */
4913 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4916 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4917 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4918 return WINED3DERR_INVALIDCALL;
4921 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4922 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4923 /* Note inc ref on returned surface */
4924 if(*ppRenderTarget != NULL)
4925 IWineD3DSurface_AddRef(*ppRenderTarget);
4929 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4931 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4932 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4933 IWineD3DSwapChainImpl *Swapchain;
4936 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4938 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4939 if(hr != WINED3D_OK) {
4940 ERR("Can't get the swapchain\n");
4944 /* Make sure to release the swapchain */
4945 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4947 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4948 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4949 return WINED3DERR_INVALIDCALL;
4951 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4952 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4953 return WINED3DERR_INVALIDCALL;
4956 if(Swapchain->frontBuffer != Front) {
4957 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4959 if(Swapchain->frontBuffer)
4960 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4961 Swapchain->frontBuffer = Front;
4963 if(Swapchain->frontBuffer) {
4964 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4968 if(Back && !Swapchain->backBuffer) {
4969 /* We need memory for the back buffer array - only one back buffer this way */
4970 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4971 if(!Swapchain->backBuffer) {
4972 ERR("Out of memory\n");
4973 return E_OUTOFMEMORY;
4977 if(Swapchain->backBuffer[0] != Back) {
4978 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4980 if(!Swapchain->backBuffer[0]) {
4981 /* GL was told to draw to the front buffer at creation,
4984 glDrawBuffer(GL_BACK);
4985 checkGLcall("glDrawBuffer(GL_BACK)");
4986 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4987 Swapchain->presentParms.BackBufferCount = 1;
4989 /* That makes problems - disable for now */
4990 /* glDrawBuffer(GL_FRONT); */
4991 checkGLcall("glDrawBuffer(GL_FRONT)");
4992 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4993 Swapchain->presentParms.BackBufferCount = 0;
4997 if(Swapchain->backBuffer[0])
4998 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4999 Swapchain->backBuffer[0] = Back;
5001 if(Swapchain->backBuffer[0]) {
5002 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5004 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5012 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5014 *ppZStencilSurface = This->depthStencilBuffer;
5015 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5017 if(*ppZStencilSurface != NULL) {
5018 /* Note inc ref on returned surface */
5019 IWineD3DSurface_AddRef(*ppZStencilSurface);
5024 static void bind_fbo(IWineD3DDevice *iface) {
5025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5028 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5029 checkGLcall("glGenFramebuffersEXT()");
5031 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5032 checkGLcall("glBindFramebuffer()");
5035 /* TODO: Handle stencil attachments */
5036 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5038 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5040 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5044 if (depth_stencil_impl) {
5045 GLenum texttarget, target;
5046 GLint old_binding = 0;
5048 IWineD3DSurface_PreLoad(depth_stencil);
5049 texttarget = depth_stencil_impl->glDescription.target;
5050 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5052 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5053 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5054 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5055 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5056 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5057 glBindTexture(target, old_binding);
5059 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5060 checkGLcall("glFramebufferTexture2DEXT()");
5062 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5063 checkGLcall("glFramebufferTexture2DEXT()");
5066 if (!This->render_offscreen) {
5067 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5068 checkGLcall("glBindFramebuffer()");
5072 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5074 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5076 if (idx >= GL_LIMITS(buffers)) {
5077 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5083 GLenum texttarget, target;
5084 GLint old_binding = 0;
5086 IWineD3DSurface_PreLoad(render_target);
5087 texttarget = rtimpl->glDescription.target;
5088 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5090 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5091 glBindTexture(target, rtimpl->glDescription.textureName);
5092 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5093 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5094 glBindTexture(target, old_binding);
5096 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5097 checkGLcall("glFramebufferTexture2DEXT()");
5099 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5101 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5102 checkGLcall("glFramebufferTexture2DEXT()");
5104 This->draw_buffers[idx] = GL_NONE;
5107 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5108 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5109 checkGLcall("glDrawBuffers()");
5112 if (!This->render_offscreen) {
5113 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5114 checkGLcall("glBindFramebuffer()");
5118 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 WINED3DVIEWPORT viewport;
5122 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5124 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5125 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5126 return WINED3DERR_INVALIDCALL;
5129 /* MSDN says that null disables the render target
5130 but a device must always be associated with a render target
5131 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5133 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5136 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5137 FIXME("Trying to set render target 0 to NULL\n");
5138 return WINED3DERR_INVALIDCALL;
5140 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5141 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);
5142 return WINED3DERR_INVALIDCALL;
5145 /* If we are trying to set what we already have, don't bother */
5146 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5147 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5150 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5151 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5152 This->render_targets[RenderTargetIndex] = pRenderTarget;
5154 /* Render target 0 is special */
5155 if(RenderTargetIndex == 0) {
5156 /* Finally, reset the viewport as the MSDN states. */
5157 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5158 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5161 viewport.MaxZ = 1.0f;
5162 viewport.MinZ = 0.0f;
5163 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5165 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5167 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5168 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5170 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5172 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5173 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5178 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5180 HRESULT hr = WINED3D_OK;
5181 IWineD3DSurface *tmp;
5183 TRACE("(%p) Swapping z-buffer\n",This);
5185 if (pNewZStencil == This->stencilBufferTarget) {
5186 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5188 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5189 * depending on the renter target implementation being used.
5190 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5191 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5192 * stencil buffer and incure an extra memory overhead
5193 ******************************************************/
5196 tmp = This->stencilBufferTarget;
5197 This->stencilBufferTarget = pNewZStencil;
5198 /* should we be calling the parent or the wined3d surface? */
5199 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5200 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5202 /** TODO: glEnable/glDisable on depth/stencil depending on
5203 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5204 **********************************************************/
5205 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5206 set_depth_stencil_fbo(iface, pNewZStencil);
5213 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5214 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5216 /* TODO: the use of Impl is deprecated. */
5217 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5219 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5221 /* some basic validation checks */
5222 if(This->cursorTexture) {
5224 glDeleteTextures(1, &This->cursorTexture);
5226 This->cursorTexture = 0;
5230 /* MSDN: Cursor must be A8R8G8B8 */
5231 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5232 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5233 return WINED3DERR_INVALIDCALL;
5236 /* MSDN: Cursor must be smaller than the display mode */
5237 if(pSur->currentDesc.Width > This->ddraw_width ||
5238 pSur->currentDesc.Height > This->ddraw_height) {
5239 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);
5240 return WINED3DERR_INVALIDCALL;
5243 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5244 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5245 * Texture and Blitting code to draw the cursor
5247 pSur->Flags |= SFLAG_FORCELOAD;
5248 IWineD3DSurface_PreLoad(pCursorBitmap);
5249 pSur->Flags &= ~SFLAG_FORCELOAD;
5250 /* Do not store the surface's pointer because the application may release
5251 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5252 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5254 This->cursorTexture = pSur->glDescription.textureName;
5255 This->cursorWidth = pSur->currentDesc.Width;
5256 This->cursorHeight = pSur->currentDesc.Height;
5257 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5260 This->xHotSpot = XHotSpot;
5261 This->yHotSpot = YHotSpot;
5265 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5267 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5269 This->xScreenSpace = XScreenSpace;
5270 This->yScreenSpace = YScreenSpace;
5276 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5278 BOOL oldVisible = This->bCursorVisible;
5279 TRACE("(%p) : visible(%d)\n", This, bShow);
5281 if(This->cursorTexture)
5282 This->bCursorVisible = bShow;
5287 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5289 TRACE("(%p) : state (%u)\n", This, This->state);
5290 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5291 switch (This->state) {
5294 case WINED3DERR_DEVICELOST:
5296 ResourceList *resourceList = This->resources;
5297 while (NULL != resourceList) {
5298 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5299 return WINED3DERR_DEVICENOTRESET;
5300 resourceList = resourceList->next;
5302 return WINED3DERR_DEVICELOST;
5304 case WINED3DERR_DRIVERINTERNALERROR:
5305 return WINED3DERR_DRIVERINTERNALERROR;
5309 return WINED3DERR_DRIVERINTERNALERROR;
5313 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5315 /** FIXME: Resource tracking needs to be done,
5316 * The closes we can do to this is set the priorities of all managed textures low
5317 * and then reset them.
5318 ***********************************************************/
5319 FIXME("(%p) : stub\n", This);
5323 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5324 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5326 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5327 if(surface->Flags & SFLAG_DIBSECTION) {
5328 /* Release the DC */
5329 SelectObject(surface->hDC, surface->dib.holdbitmap);
5330 DeleteDC(surface->hDC);
5331 /* Release the DIB section */
5332 DeleteObject(surface->dib.DIBsection);
5333 surface->dib.bitmap_data = NULL;
5334 surface->resource.allocatedMemory = NULL;
5335 surface->Flags &= ~SFLAG_DIBSECTION;
5337 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5338 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5339 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5340 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5341 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5343 surface->pow2Width = surface->pow2Height = 1;
5344 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5345 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5347 if(surface->glDescription.textureName) {
5349 glDeleteTextures(1, &surface->glDescription.textureName);
5351 surface->glDescription.textureName = 0;
5353 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5354 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5355 surface->Flags |= SFLAG_NONPOW2;
5357 surface->Flags &= ~SFLAG_NONPOW2;
5359 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5360 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5363 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5365 IWineD3DSwapChainImpl *swapchain;
5367 BOOL DisplayModeChanged = FALSE;
5368 WINED3DDISPLAYMODE mode;
5369 TRACE("(%p)\n", This);
5371 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5373 ERR("Failed to get the first implicit swapchain\n");
5377 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5378 * on an existing gl context, so there's no real need for recreation.
5380 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5382 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5384 TRACE("New params:\n");
5385 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5386 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5387 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5388 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5389 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5390 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5391 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5392 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5393 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5394 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5395 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5396 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5397 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5399 /* No special treatment of these parameters. Just store them */
5400 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5401 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5402 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5403 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5405 /* What to do about these? */
5406 if(pPresentationParameters->BackBufferCount != 0 &&
5407 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5408 ERR("Cannot change the back buffer count yet\n");
5410 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5411 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5412 ERR("Cannot change the back buffer format yet\n");
5414 if(pPresentationParameters->hDeviceWindow != NULL &&
5415 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5416 ERR("Cannot change the device window yet\n");
5418 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5419 ERR("What do do about a changed auto depth stencil parameter?\n");
5422 if(pPresentationParameters->Windowed) {
5423 mode.Width = swapchain->orig_width;
5424 mode.Height = swapchain->orig_height;
5425 mode.RefreshRate = 0;
5426 mode.Format = swapchain->presentParms.BackBufferFormat;
5428 mode.Width = pPresentationParameters->BackBufferWidth;
5429 mode.Height = pPresentationParameters->BackBufferHeight;
5430 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5431 mode.Format = swapchain->presentParms.BackBufferFormat;
5434 /* Should Width == 800 && Height == 0 set 800x600? */
5435 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5436 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5437 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5444 vp.Width = pPresentationParameters->BackBufferWidth;
5445 vp.Height = pPresentationParameters->BackBufferHeight;
5449 if(!pPresentationParameters->Windowed) {
5450 DisplayModeChanged = TRUE;
5452 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5453 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5455 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5456 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5457 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5460 /* Now set the new viewport */
5461 IWineD3DDevice_SetViewport(iface, &vp);
5464 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5465 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5466 DisplayModeChanged) {
5468 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5469 if(!pPresentationParameters->Windowed) {
5470 IWineD3DDevice_SetFullscreen(iface, TRUE);
5473 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5475 /* Switching out of fullscreen mode? First set the original res, then change the window */
5476 if(pPresentationParameters->Windowed) {
5477 IWineD3DDevice_SetFullscreen(iface, FALSE);
5479 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5482 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5486 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5488 /** FIXME: always true at the moment **/
5489 if(!bEnableDialogs) {
5490 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5496 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5498 TRACE("(%p) : pParameters %p\n", This, pParameters);
5500 *pParameters = This->createParms;
5504 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5505 IWineD3DSwapChain *swapchain;
5506 HRESULT hrc = WINED3D_OK;
5508 TRACE("Relaying to swapchain\n");
5510 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5511 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5512 IWineD3DSwapChain_Release(swapchain);
5517 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5518 IWineD3DSwapChain *swapchain;
5519 HRESULT hrc = WINED3D_OK;
5521 TRACE("Relaying to swapchain\n");
5523 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5524 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5525 IWineD3DSwapChain_Release(swapchain);
5531 /** ********************************************************
5532 * Notification functions
5533 ** ********************************************************/
5534 /** This function must be called in the release of a resource when ref == 0,
5535 * the contents of resource must still be correct,
5536 * any handels to other resource held by the caller must be closed
5537 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5538 *****************************************************/
5539 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5541 ResourceList* resourceList;
5543 TRACE("(%p) : resource %p\n", This, resource);
5545 EnterCriticalSection(&resourceStoreCriticalSection);
5547 /* add a new texture to the frot of the linked list */
5548 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5549 resourceList->resource = resource;
5551 /* Get the old head */
5552 resourceList->next = This->resources;
5554 This->resources = resourceList;
5555 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5558 LeaveCriticalSection(&resourceStoreCriticalSection);
5563 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5565 ResourceList* resourceList = NULL;
5566 ResourceList* previousResourceList = NULL;
5568 TRACE("(%p) : resource %p\n", This, resource);
5571 EnterCriticalSection(&resourceStoreCriticalSection);
5573 resourceList = This->resources;
5575 while (resourceList != NULL) {
5576 if(resourceList->resource == resource) break;
5577 previousResourceList = resourceList;
5578 resourceList = resourceList->next;
5581 if (resourceList == NULL) {
5582 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5584 LeaveCriticalSection(&resourceStoreCriticalSection);
5588 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5590 /* make sure we don't leave a hole in the list */
5591 if (previousResourceList != NULL) {
5592 previousResourceList->next = resourceList->next;
5594 This->resources = resourceList->next;
5598 LeaveCriticalSection(&resourceStoreCriticalSection);
5604 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5608 TRACE("(%p) : resource %p\n", This, resource);
5609 switch(IWineD3DResource_GetType(resource)){
5610 case WINED3DRTYPE_SURFACE:
5611 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5613 case WINED3DRTYPE_TEXTURE:
5614 case WINED3DRTYPE_CUBETEXTURE:
5615 case WINED3DRTYPE_VOLUMETEXTURE:
5616 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5617 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5618 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5619 This->stateBlock->textures[counter] = NULL;
5621 if (This->updateStateBlock != This->stateBlock ){
5622 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5623 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5624 This->updateStateBlock->textures[counter] = NULL;
5629 case WINED3DRTYPE_VOLUME:
5630 /* TODO: nothing really? */
5632 case WINED3DRTYPE_VERTEXBUFFER:
5633 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5636 TRACE("Cleaning up stream pointers\n");
5638 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5639 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5640 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5642 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5643 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5644 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5645 This->updateStateBlock->streamSource[streamNumber] = 0;
5646 /* Set changed flag? */
5649 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) */
5650 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5651 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5652 This->stateBlock->streamSource[streamNumber] = 0;
5655 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5656 else { /* This shouldn't happen */
5657 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5664 case WINED3DRTYPE_INDEXBUFFER:
5665 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5666 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5667 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5668 This->updateStateBlock->pIndexData = NULL;
5671 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5672 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5673 This->stateBlock->pIndexData = NULL;
5679 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5684 /* Remove the resoruce from the resourceStore */
5685 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5687 TRACE("Resource released\n");
5691 /**********************************************************
5692 * IWineD3DDevice VTbl follows
5693 **********************************************************/
5695 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5697 /*** IUnknown methods ***/
5698 IWineD3DDeviceImpl_QueryInterface,
5699 IWineD3DDeviceImpl_AddRef,
5700 IWineD3DDeviceImpl_Release,
5701 /*** IWineD3DDevice methods ***/
5702 IWineD3DDeviceImpl_GetParent,
5703 /*** Creation methods**/
5704 IWineD3DDeviceImpl_CreateVertexBuffer,
5705 IWineD3DDeviceImpl_CreateIndexBuffer,
5706 IWineD3DDeviceImpl_CreateStateBlock,
5707 IWineD3DDeviceImpl_CreateSurface,
5708 IWineD3DDeviceImpl_CreateTexture,
5709 IWineD3DDeviceImpl_CreateVolumeTexture,
5710 IWineD3DDeviceImpl_CreateVolume,
5711 IWineD3DDeviceImpl_CreateCubeTexture,
5712 IWineD3DDeviceImpl_CreateQuery,
5713 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5714 IWineD3DDeviceImpl_CreateVertexDeclaration,
5715 IWineD3DDeviceImpl_CreateVertexShader,
5716 IWineD3DDeviceImpl_CreatePixelShader,
5717 IWineD3DDeviceImpl_CreatePalette,
5718 /*** Odd functions **/
5719 IWineD3DDeviceImpl_Init3D,
5720 IWineD3DDeviceImpl_Uninit3D,
5721 IWineD3DDeviceImpl_SetFullscreen,
5722 IWineD3DDeviceImpl_EvictManagedResources,
5723 IWineD3DDeviceImpl_GetAvailableTextureMem,
5724 IWineD3DDeviceImpl_GetBackBuffer,
5725 IWineD3DDeviceImpl_GetCreationParameters,
5726 IWineD3DDeviceImpl_GetDeviceCaps,
5727 IWineD3DDeviceImpl_GetDirect3D,
5728 IWineD3DDeviceImpl_GetDisplayMode,
5729 IWineD3DDeviceImpl_SetDisplayMode,
5730 IWineD3DDeviceImpl_GetHWND,
5731 IWineD3DDeviceImpl_SetHWND,
5732 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5733 IWineD3DDeviceImpl_GetRasterStatus,
5734 IWineD3DDeviceImpl_GetSwapChain,
5735 IWineD3DDeviceImpl_Reset,
5736 IWineD3DDeviceImpl_SetDialogBoxMode,
5737 IWineD3DDeviceImpl_SetCursorProperties,
5738 IWineD3DDeviceImpl_SetCursorPosition,
5739 IWineD3DDeviceImpl_ShowCursor,
5740 IWineD3DDeviceImpl_TestCooperativeLevel,
5741 /*** Getters and setters **/
5742 IWineD3DDeviceImpl_SetClipPlane,
5743 IWineD3DDeviceImpl_GetClipPlane,
5744 IWineD3DDeviceImpl_SetClipStatus,
5745 IWineD3DDeviceImpl_GetClipStatus,
5746 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5747 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5748 IWineD3DDeviceImpl_SetDepthStencilSurface,
5749 IWineD3DDeviceImpl_GetDepthStencilSurface,
5750 IWineD3DDeviceImpl_SetFVF,
5751 IWineD3DDeviceImpl_GetFVF,
5752 IWineD3DDeviceImpl_SetGammaRamp,
5753 IWineD3DDeviceImpl_GetGammaRamp,
5754 IWineD3DDeviceImpl_SetIndices,
5755 IWineD3DDeviceImpl_GetIndices,
5756 IWineD3DDeviceImpl_SetBasevertexIndex,
5757 IWineD3DDeviceImpl_SetLight,
5758 IWineD3DDeviceImpl_GetLight,
5759 IWineD3DDeviceImpl_SetLightEnable,
5760 IWineD3DDeviceImpl_GetLightEnable,
5761 IWineD3DDeviceImpl_SetMaterial,
5762 IWineD3DDeviceImpl_GetMaterial,
5763 IWineD3DDeviceImpl_SetNPatchMode,
5764 IWineD3DDeviceImpl_GetNPatchMode,
5765 IWineD3DDeviceImpl_SetPaletteEntries,
5766 IWineD3DDeviceImpl_GetPaletteEntries,
5767 IWineD3DDeviceImpl_SetPixelShader,
5768 IWineD3DDeviceImpl_GetPixelShader,
5769 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5770 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5771 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5772 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5773 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5774 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5775 IWineD3DDeviceImpl_SetRenderState,
5776 IWineD3DDeviceImpl_GetRenderState,
5777 IWineD3DDeviceImpl_SetRenderTarget,
5778 IWineD3DDeviceImpl_GetRenderTarget,
5779 IWineD3DDeviceImpl_SetFrontBackBuffers,
5780 IWineD3DDeviceImpl_SetSamplerState,
5781 IWineD3DDeviceImpl_GetSamplerState,
5782 IWineD3DDeviceImpl_SetScissorRect,
5783 IWineD3DDeviceImpl_GetScissorRect,
5784 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5785 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5786 IWineD3DDeviceImpl_SetStreamSource,
5787 IWineD3DDeviceImpl_GetStreamSource,
5788 IWineD3DDeviceImpl_SetStreamSourceFreq,
5789 IWineD3DDeviceImpl_GetStreamSourceFreq,
5790 IWineD3DDeviceImpl_SetTexture,
5791 IWineD3DDeviceImpl_GetTexture,
5792 IWineD3DDeviceImpl_SetTextureStageState,
5793 IWineD3DDeviceImpl_GetTextureStageState,
5794 IWineD3DDeviceImpl_SetTransform,
5795 IWineD3DDeviceImpl_GetTransform,
5796 IWineD3DDeviceImpl_SetVertexDeclaration,
5797 IWineD3DDeviceImpl_GetVertexDeclaration,
5798 IWineD3DDeviceImpl_SetVertexShader,
5799 IWineD3DDeviceImpl_GetVertexShader,
5800 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5801 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5802 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5803 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5804 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5805 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5806 IWineD3DDeviceImpl_SetViewport,
5807 IWineD3DDeviceImpl_GetViewport,
5808 IWineD3DDeviceImpl_MultiplyTransform,
5809 IWineD3DDeviceImpl_ValidateDevice,
5810 IWineD3DDeviceImpl_ProcessVertices,
5811 /*** State block ***/
5812 IWineD3DDeviceImpl_BeginStateBlock,
5813 IWineD3DDeviceImpl_EndStateBlock,
5814 /*** Scene management ***/
5815 IWineD3DDeviceImpl_BeginScene,
5816 IWineD3DDeviceImpl_EndScene,
5817 IWineD3DDeviceImpl_Present,
5818 IWineD3DDeviceImpl_Clear,
5820 IWineD3DDeviceImpl_DrawPrimitive,
5821 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5822 IWineD3DDeviceImpl_DrawPrimitiveUP,
5823 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5824 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5825 IWineD3DDeviceImpl_DrawRectPatch,
5826 IWineD3DDeviceImpl_DrawTriPatch,
5827 IWineD3DDeviceImpl_DeletePatch,
5828 IWineD3DDeviceImpl_ColorFill,
5829 IWineD3DDeviceImpl_UpdateTexture,
5830 IWineD3DDeviceImpl_UpdateSurface,
5831 IWineD3DDeviceImpl_GetFrontBufferData,
5832 /*** object tracking ***/
5833 IWineD3DDeviceImpl_ResourceReleased
5837 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5838 WINED3DRS_ALPHABLENDENABLE ,
5839 WINED3DRS_ALPHAFUNC ,
5840 WINED3DRS_ALPHAREF ,
5841 WINED3DRS_ALPHATESTENABLE ,
5843 WINED3DRS_COLORWRITEENABLE ,
5844 WINED3DRS_DESTBLEND ,
5845 WINED3DRS_DITHERENABLE ,
5846 WINED3DRS_FILLMODE ,
5847 WINED3DRS_FOGDENSITY ,
5849 WINED3DRS_FOGSTART ,
5850 WINED3DRS_LASTPIXEL ,
5851 WINED3DRS_SHADEMODE ,
5852 WINED3DRS_SRCBLEND ,
5853 WINED3DRS_STENCILENABLE ,
5854 WINED3DRS_STENCILFAIL ,
5855 WINED3DRS_STENCILFUNC ,
5856 WINED3DRS_STENCILMASK ,
5857 WINED3DRS_STENCILPASS ,
5858 WINED3DRS_STENCILREF ,
5859 WINED3DRS_STENCILWRITEMASK ,
5860 WINED3DRS_STENCILZFAIL ,
5861 WINED3DRS_TEXTUREFACTOR ,
5872 WINED3DRS_ZWRITEENABLE
5875 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5876 WINED3DTSS_ADDRESSW ,
5877 WINED3DTSS_ALPHAARG0 ,
5878 WINED3DTSS_ALPHAARG1 ,
5879 WINED3DTSS_ALPHAARG2 ,
5880 WINED3DTSS_ALPHAOP ,
5881 WINED3DTSS_BUMPENVLOFFSET ,
5882 WINED3DTSS_BUMPENVLSCALE ,
5883 WINED3DTSS_BUMPENVMAT00 ,
5884 WINED3DTSS_BUMPENVMAT01 ,
5885 WINED3DTSS_BUMPENVMAT10 ,
5886 WINED3DTSS_BUMPENVMAT11 ,
5887 WINED3DTSS_COLORARG0 ,
5888 WINED3DTSS_COLORARG1 ,
5889 WINED3DTSS_COLORARG2 ,
5890 WINED3DTSS_COLOROP ,
5891 WINED3DTSS_RESULTARG ,
5892 WINED3DTSS_TEXCOORDINDEX ,
5893 WINED3DTSS_TEXTURETRANSFORMFLAGS
5896 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5897 WINED3DSAMP_ADDRESSU ,
5898 WINED3DSAMP_ADDRESSV ,
5899 WINED3DSAMP_ADDRESSW ,
5900 WINED3DSAMP_BORDERCOLOR ,
5901 WINED3DSAMP_MAGFILTER ,
5902 WINED3DSAMP_MINFILTER ,
5903 WINED3DSAMP_MIPFILTER ,
5904 WINED3DSAMP_MIPMAPLODBIAS ,
5905 WINED3DSAMP_MAXMIPLEVEL ,
5906 WINED3DSAMP_MAXANISOTROPY ,
5907 WINED3DSAMP_SRGBTEXTURE ,
5908 WINED3DSAMP_ELEMENTINDEX
5911 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5913 WINED3DRS_AMBIENTMATERIALSOURCE ,
5914 WINED3DRS_CLIPPING ,
5915 WINED3DRS_CLIPPLANEENABLE ,
5916 WINED3DRS_COLORVERTEX ,
5917 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5918 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5919 WINED3DRS_FOGDENSITY ,
5921 WINED3DRS_FOGSTART ,
5922 WINED3DRS_FOGTABLEMODE ,
5923 WINED3DRS_FOGVERTEXMODE ,
5924 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5925 WINED3DRS_LIGHTING ,
5926 WINED3DRS_LOCALVIEWER ,
5927 WINED3DRS_MULTISAMPLEANTIALIAS ,
5928 WINED3DRS_MULTISAMPLEMASK ,
5929 WINED3DRS_NORMALIZENORMALS ,
5930 WINED3DRS_PATCHEDGESTYLE ,
5931 WINED3DRS_POINTSCALE_A ,
5932 WINED3DRS_POINTSCALE_B ,
5933 WINED3DRS_POINTSCALE_C ,
5934 WINED3DRS_POINTSCALEENABLE ,
5935 WINED3DRS_POINTSIZE ,
5936 WINED3DRS_POINTSIZE_MAX ,
5937 WINED3DRS_POINTSIZE_MIN ,
5938 WINED3DRS_POINTSPRITEENABLE ,
5939 WINED3DRS_RANGEFOGENABLE ,
5940 WINED3DRS_SPECULARMATERIALSOURCE ,
5941 WINED3DRS_TWEENFACTOR ,
5942 WINED3DRS_VERTEXBLEND
5945 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5946 WINED3DTSS_TEXCOORDINDEX ,
5947 WINED3DTSS_TEXTURETRANSFORMFLAGS
5950 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5951 WINED3DSAMP_DMAPOFFSET
5954 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5955 DWORD rep = StateTable[state].representative;
5959 WineD3DContext *context;
5962 for(i = 0; i < This->numContexts; i++) {
5963 context = This->contexts[i];
5964 if(isStateDirty(context, rep)) continue;
5966 context->dirtyArray[context->numDirtyEntries++] = rep;
5969 context->isStateDirty[idx] |= (1 << shift);