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);
450 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
451 * restored on the next draw
453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
458 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
459 error = glGetError();
460 if(error != GL_NO_ERROR || object->vbo == 0) {
461 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
465 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
466 error = glGetError();
467 if(error != GL_NO_ERROR) {
468 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
472 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
473 * copy no readback will be needed
475 glUsage = GL_STATIC_DRAW;
476 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
477 error = glGetError();
478 if(error != GL_NO_ERROR) {
479 ERR("Failed to initialize the index buffer\n");
483 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
487 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
488 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
493 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
494 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
495 HANDLE *sharedHandle, IUnknown *parent) {
496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
497 IWineD3DIndexBufferImpl *object;
498 TRACE("(%p) Creating index buffer\n", This);
500 /* Allocate the storage for the device */
501 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
503 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
504 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
507 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
508 CreateIndexBufferVBO(This, object);
511 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
512 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
513 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
518 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
521 IWineD3DStateBlockImpl *object;
525 D3DCREATEOBJECTINSTANCE(object, StateBlock)
526 object->blockType = Type;
528 for(i = 0; i < LIGHTMAP_SIZE; i++) {
529 list_init(&object->lightMap[i]);
532 /* Special case - Used during initialization to produce a placeholder stateblock
533 so other functions called can update a state block */
534 if (Type == WINED3DSBT_INIT) {
535 /* Don't bother increasing the reference count otherwise a device will never
536 be freed due to circular dependencies */
540 temp_result = allocate_shader_constants(object);
541 if (WINED3D_OK != temp_result)
544 /* Otherwise, might as well set the whole state block to the appropriate values */
545 if (This->stateBlock != NULL)
546 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
548 memset(object->streamFreq, 1, sizeof(object->streamFreq));
550 /* Reset the ref and type after kludging it */
551 object->wineD3DDevice = This;
553 object->blockType = Type;
555 TRACE("Updating changed flags appropriate for type %d\n", Type);
557 if (Type == WINED3DSBT_ALL) {
559 TRACE("ALL => Pretend everything has changed\n");
560 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
562 /* Lights are not part of the changed / set structure */
563 for(j = 0; j < LIGHTMAP_SIZE; j++) {
565 LIST_FOR_EACH(e, &object->lightMap[j]) {
566 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
567 light->changed = TRUE;
568 light->enabledChanged = TRUE;
571 } else if (Type == WINED3DSBT_PIXELSTATE) {
573 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
574 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
576 object->changed.pixelShader = TRUE;
578 /* Pixel Shader Constants */
579 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
580 object->changed.pixelShaderConstantsF[i] = TRUE;
581 for (i = 0; i < MAX_CONST_B; ++i)
582 object->changed.pixelShaderConstantsB[i] = TRUE;
583 for (i = 0; i < MAX_CONST_I; ++i)
584 object->changed.pixelShaderConstantsI[i] = TRUE;
586 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
587 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
589 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
590 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
591 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
594 for (j = 0 ; j < 16; j++) {
595 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
597 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
601 } else if (Type == WINED3DSBT_VERTEXSTATE) {
603 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
604 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
606 object->changed.vertexShader = TRUE;
608 /* Vertex Shader Constants */
609 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
610 object->changed.vertexShaderConstantsF[i] = TRUE;
611 for (i = 0; i < MAX_CONST_B; ++i)
612 object->changed.vertexShaderConstantsB[i] = TRUE;
613 for (i = 0; i < MAX_CONST_I; ++i)
614 object->changed.vertexShaderConstantsI[i] = TRUE;
616 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
617 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
619 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
620 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
621 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
624 for (j = 0 ; j < 16; j++){
625 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
626 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
630 for(j = 0; j < LIGHTMAP_SIZE; j++) {
632 LIST_FOR_EACH(e, &object->lightMap[j]) {
633 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
634 light->changed = TRUE;
635 light->enabledChanged = TRUE;
639 FIXME("Unrecognized state block type %d\n", Type);
642 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
647 /* ************************************
649 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
652 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
654 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.
656 ******************************** */
658 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) {
659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
660 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
661 unsigned int pow2Width, pow2Height;
662 unsigned int Size = 1;
663 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
664 TRACE("(%p) Create surface\n",This);
666 /** FIXME: Check ranges on the inputs are valid
669 * [in] Quality level. The valid range is between zero and one less than the level
670 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
671 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
672 * values of paired render targets, depth stencil surfaces, and the MultiSample type
674 *******************************/
679 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
681 * If this flag is set, the contents of the depth stencil buffer will be
682 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
683 * with a different depth surface.
685 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
686 ***************************/
688 if(MultisampleQuality < 0) {
689 FIXME("Invalid multisample level %d\n", MultisampleQuality);
690 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
693 if(MultisampleQuality > 0) {
694 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
695 MultisampleQuality=0;
698 /** FIXME: Check that the format is supported
700 *******************************/
702 /* Non-power2 support */
703 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
707 /* Find the nearest pow2 match */
708 pow2Width = pow2Height = 1;
709 while (pow2Width < Width) pow2Width <<= 1;
710 while (pow2Height < Height) pow2Height <<= 1;
713 if (pow2Width > Width || pow2Height > Height) {
714 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
715 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
716 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
717 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
718 This, Width, Height);
719 return WINED3DERR_NOTAVAILABLE;
723 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
724 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
726 *********************************/
727 if (WINED3DFMT_UNKNOWN == Format) {
729 } else if (Format == WINED3DFMT_DXT1) {
730 /* DXT1 is half byte per pixel */
731 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
733 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
734 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
735 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
737 /* The pitch is a multiple of 4 bytes */
738 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
742 /** Create and initialise the surface resource **/
743 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
744 /* "Standalone" surface */
745 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
747 object->currentDesc.Width = Width;
748 object->currentDesc.Height = Height;
749 object->currentDesc.MultiSampleType = MultiSample;
750 object->currentDesc.MultiSampleQuality = MultisampleQuality;
752 /* Setup some glformat defaults */
753 object->glDescription.glFormat = tableEntry->glFormat;
754 object->glDescription.glFormatInternal = tableEntry->glInternal;
755 object->glDescription.glType = tableEntry->glType;
757 object->glDescription.textureName = 0;
758 object->glDescription.level = Level;
759 object->glDescription.target = GL_TEXTURE_2D;
762 object->pow2Width = pow2Width;
763 object->pow2Height = pow2Height;
766 object->Flags = 0; /* We start without flags set */
767 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
768 object->Flags |= Discard ? SFLAG_DISCARD : 0;
769 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
770 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
773 if (WINED3DFMT_UNKNOWN != Format) {
774 object->bytesPerPixel = tableEntry->bpp;
776 object->bytesPerPixel = 0;
779 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
781 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
783 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
784 * this function is too deep to need to care about things like this.
785 * Levels need to be checked too, and possibly Type since they all affect what can be done.
786 * ****************************************/
788 case WINED3DPOOL_SCRATCH:
790 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
791 "which are mutually exclusive, setting lockable to TRUE\n");
794 case WINED3DPOOL_SYSTEMMEM:
795 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
796 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
797 case WINED3DPOOL_MANAGED:
798 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
799 "Usage of DYNAMIC which are mutually exclusive, not doing "
800 "anything just telling you.\n");
802 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
803 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
804 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
805 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
808 FIXME("(%p) Unknown pool %d\n", This, Pool);
812 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
813 FIXME("Trying to create a render target that isn't in the default pool\n");
816 /* mark the texture as dirty so that it gets loaded first time around*/
817 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
818 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
819 This, Width, Height, Format, debug_d3dformat(Format),
820 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
822 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
823 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
824 This->ddraw_primary = (IWineD3DSurface *) object;
826 /* Look at the implementation and set the correct Vtable */
829 /* Nothing to do, it's set already */
833 object->lpVtbl = &IWineGDISurface_Vtbl;
837 /* To be sure to catch this */
838 ERR("Unknown requested surface implementation %d!\n", Impl);
839 IWineD3DSurface_Release((IWineD3DSurface *) object);
840 return WINED3DERR_INVALIDCALL;
843 /* Call the private setup routine */
844 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
848 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
849 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
850 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
851 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
854 IWineD3DTextureImpl *object;
859 unsigned int pow2Width;
860 unsigned int pow2Height;
863 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
864 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
865 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
867 /* TODO: It should only be possible to create textures for formats
868 that are reported as supported */
869 if (WINED3DFMT_UNKNOWN >= Format) {
870 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
871 return WINED3DERR_INVALIDCALL;
874 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
875 D3DINITIALIZEBASETEXTURE(object->baseTexture);
876 object->width = Width;
877 object->height = Height;
879 /** Non-power2 support **/
880 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
884 /* Find the nearest pow2 match */
885 pow2Width = pow2Height = 1;
886 while (pow2Width < Width) pow2Width <<= 1;
887 while (pow2Height < Height) pow2Height <<= 1;
890 /** FIXME: add support for real non-power-two if it's provided by the video card **/
891 /* Precalculated scaling for 'faked' non power of two texture coords */
892 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
893 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
894 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
896 /* Calculate levels for mip mapping */
898 TRACE("calculating levels %d\n", object->baseTexture.levels);
899 object->baseTexture.levels++;
902 while (tmpW > 1 || tmpH > 1) {
903 tmpW = max(1, tmpW >> 1);
904 tmpH = max(1, tmpH >> 1);
905 object->baseTexture.levels++;
907 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
910 /* Generate all the surfaces */
913 for (i = 0; i < object->baseTexture.levels; i++)
915 /* use the callback to create the texture surface */
916 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
917 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
918 FIXME("Failed to create surface %p\n", object);
920 object->surfaces[i] = NULL;
921 IWineD3DTexture_Release((IWineD3DTexture *)object);
927 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
928 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
929 /* calculate the next mipmap level */
930 tmpW = max(1, tmpW >> 1);
931 tmpH = max(1, tmpH >> 1);
934 TRACE("(%p) : Created texture %p\n", This, object);
938 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
939 UINT Width, UINT Height, UINT Depth,
940 UINT Levels, DWORD Usage,
941 WINED3DFORMAT Format, WINED3DPOOL Pool,
942 IWineD3DVolumeTexture **ppVolumeTexture,
943 HANDLE *pSharedHandle, IUnknown *parent,
944 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
947 IWineD3DVolumeTextureImpl *object;
953 /* TODO: It should only be possible to create textures for formats
954 that are reported as supported */
955 if (WINED3DFMT_UNKNOWN >= Format) {
956 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
957 return WINED3DERR_INVALIDCALL;
960 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
961 D3DINITIALIZEBASETEXTURE(object->baseTexture);
963 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
964 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
966 object->width = Width;
967 object->height = Height;
968 object->depth = Depth;
970 /* Calculate levels for mip mapping */
972 object->baseTexture.levels++;
976 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
977 tmpW = max(1, tmpW >> 1);
978 tmpH = max(1, tmpH >> 1);
979 tmpD = max(1, tmpD >> 1);
980 object->baseTexture.levels++;
982 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
985 /* Generate all the surfaces */
990 for (i = 0; i < object->baseTexture.levels; i++)
993 /* Create the volume */
994 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
995 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
998 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
999 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1000 *ppVolumeTexture = NULL;
1004 /* Set its container to this object */
1005 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1007 /* calcualte the next mipmap level */
1008 tmpW = max(1, tmpW >> 1);
1009 tmpH = max(1, tmpH >> 1);
1010 tmpD = max(1, tmpD >> 1);
1013 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1014 TRACE("(%p) : Created volume texture %p\n", This, object);
1018 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1019 UINT Width, UINT Height, UINT Depth,
1021 WINED3DFORMAT Format, WINED3DPOOL Pool,
1022 IWineD3DVolume** ppVolume,
1023 HANDLE* pSharedHandle, IUnknown *parent) {
1025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1026 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1027 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1029 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1031 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1032 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1034 object->currentDesc.Width = Width;
1035 object->currentDesc.Height = Height;
1036 object->currentDesc.Depth = Depth;
1037 object->bytesPerPixel = formatDesc->bpp;
1039 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1040 object->lockable = TRUE;
1041 object->locked = FALSE;
1042 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1043 object->dirty = TRUE;
1045 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1048 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1049 UINT Levels, DWORD Usage,
1050 WINED3DFORMAT Format, WINED3DPOOL Pool,
1051 IWineD3DCubeTexture **ppCubeTexture,
1052 HANDLE *pSharedHandle, IUnknown *parent,
1053 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1056 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1060 unsigned int pow2EdgeLength = EdgeLength;
1062 /* TODO: It should only be possible to create textures for formats
1063 that are reported as supported */
1064 if (WINED3DFMT_UNKNOWN >= Format) {
1065 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1066 return WINED3DERR_INVALIDCALL;
1069 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1070 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1072 TRACE("(%p) Create Cube Texture\n", This);
1074 /** Non-power2 support **/
1076 /* Find the nearest pow2 match */
1078 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1080 object->edgeLength = EdgeLength;
1081 /* TODO: support for native non-power 2 */
1082 /* Precalculated scaling for 'faked' non power of two texture coords */
1083 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 /* Calculate levels for mip mapping */
1087 object->baseTexture.levels++;
1090 tmpW = max(1, tmpW >> 1);
1091 object->baseTexture.levels++;
1093 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1096 /* Generate all the surfaces */
1098 for (i = 0; i < object->baseTexture.levels; i++) {
1100 /* Create the 6 faces */
1101 for (j = 0; j < 6; j++) {
1103 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1104 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1106 if(hr!= WINED3D_OK) {
1110 for (l = 0; l < j; l++) {
1111 IWineD3DSurface_Release(object->surfaces[j][i]);
1113 for (k = 0; k < i; k++) {
1114 for (l = 0; l < 6; l++) {
1115 IWineD3DSurface_Release(object->surfaces[l][j]);
1119 FIXME("(%p) Failed to create surface\n",object);
1120 HeapFree(GetProcessHeap(),0,object);
1121 *ppCubeTexture = NULL;
1124 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1125 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1127 tmpW = max(1, tmpW >> 1);
1130 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1131 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1137 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1138 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1140 /* Just a check to see if we support this type of query */
1142 case WINED3DQUERYTYPE_OCCLUSION:
1143 TRACE("(%p) occlusion query\n", This);
1144 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1147 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1150 case WINED3DQUERYTYPE_EVENT:
1151 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1152 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1154 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1158 case WINED3DQUERYTYPE_VCACHE:
1159 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1160 case WINED3DQUERYTYPE_VERTEXSTATS:
1161 case WINED3DQUERYTYPE_TIMESTAMP:
1162 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1163 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1164 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1165 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1166 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1167 case WINED3DQUERYTYPE_PIXELTIMINGS:
1168 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1169 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1171 FIXME("(%p) Unhandled query type %d\n", This, Type);
1173 if(NULL == ppQuery || hr != WINED3D_OK) {
1177 D3DCREATEOBJECTINSTANCE(object, Query)
1178 object->type = Type;
1179 /* allocated the 'extended' data based on the type of query requested */
1181 case WINED3DQUERYTYPE_OCCLUSION:
1182 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1183 TRACE("(%p) Allocating data for an occlusion query\n", This);
1184 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1185 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1188 case WINED3DQUERYTYPE_VCACHE:
1189 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1190 case WINED3DQUERYTYPE_VERTEXSTATS:
1191 case WINED3DQUERYTYPE_EVENT:
1192 case WINED3DQUERYTYPE_TIMESTAMP:
1193 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1194 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1195 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1196 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1197 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1198 case WINED3DQUERYTYPE_PIXELTIMINGS:
1199 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1200 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1202 object->extendedData = 0;
1203 FIXME("(%p) Unhandled query type %d\n",This , Type);
1205 TRACE("(%p) : Created Query %p\n", This, object);
1209 /*****************************************************************************
1210 * IWineD3DDeviceImpl_SetupFullscreenWindow
1212 * Helper function that modifies a HWND's Style and ExStyle for proper
1216 * iface: Pointer to the IWineD3DDevice interface
1217 * window: Window to setup
1219 *****************************************************************************/
1220 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1223 LONG style, exStyle;
1224 /* Don't do anything if an original style is stored.
1225 * That shouldn't happen
1227 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1228 if (This->style || This->exStyle) {
1229 ERR("(%p): Want to change the window parameters of HWND %p, but "
1230 "another style is stored for restoration afterwards\n", This, window);
1233 /* Get the parameters and save them */
1234 style = GetWindowLongW(window, GWL_STYLE);
1235 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1236 This->style = style;
1237 This->exStyle = exStyle;
1239 /* Filter out window decorations */
1240 style &= ~WS_CAPTION;
1241 style &= ~WS_THICKFRAME;
1242 exStyle &= ~WS_EX_WINDOWEDGE;
1243 exStyle &= ~WS_EX_CLIENTEDGE;
1245 /* Make sure the window is managed, otherwise we won't get keyboard input */
1246 style |= WS_POPUP | WS_SYSMENU;
1248 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1249 This->style, This->exStyle, style, exStyle);
1251 SetWindowLongW(window, GWL_STYLE, style);
1252 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1254 /* Inform the window about the update. */
1255 SetWindowPos(window, HWND_TOP, 0, 0,
1256 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1257 ShowWindow(window, SW_NORMAL);
1260 /*****************************************************************************
1261 * IWineD3DDeviceImpl_RestoreWindow
1263 * Helper function that restores a windows' properties when taking it out
1264 * of fullscreen mode
1267 * iface: Pointer to the IWineD3DDevice interface
1268 * window: Window to setup
1270 *****************************************************************************/
1271 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1275 * switch, do nothing
1277 if (!This->style && !This->exStyle) return;
1279 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1280 This, window, This->style, This->exStyle);
1282 SetWindowLongW(window, GWL_STYLE, This->style);
1283 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1285 /* Delete the old values */
1289 /* Inform the window about the update */
1290 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1291 0, 0, 0, 0, /* Pos, Size, ignored */
1292 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1295 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1298 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1299 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1303 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1304 HRESULT hr = WINED3D_OK;
1305 IUnknown *bufferParent;
1308 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1310 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1311 * does a device hold a reference to a swap chain giving them a lifetime of the device
1312 * or does the swap chain notify the device of its destruction.
1313 *******************************/
1315 /* Check the params */
1316 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1317 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1318 return WINED3DERR_INVALIDCALL;
1319 } else if (pPresentationParameters->BackBufferCount > 1) {
1320 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");
1323 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1325 /*********************
1326 * Lookup the window Handle and the relating X window handle
1327 ********************/
1329 /* Setup hwnd we are using, plus which display this equates to */
1330 object->win_handle = pPresentationParameters->hDeviceWindow;
1331 if (!object->win_handle) {
1332 object->win_handle = This->createParms.hFocusWindow;
1335 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1336 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1337 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1338 return WINED3DERR_NOTAVAILABLE;
1340 hDc = GetDC(object->win_handle);
1341 display = get_display(hDc);
1342 ReleaseDC(object->win_handle, hDc);
1343 TRACE("Using a display of %p %p\n", display, hDc);
1345 if (NULL == display || NULL == hDc) {
1346 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1347 return WINED3DERR_NOTAVAILABLE;
1350 if (object->win == 0) {
1351 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1352 return WINED3DERR_NOTAVAILABLE;
1355 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1356 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1357 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1359 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1360 * then the corresponding dimension of the client area of the hDeviceWindow
1361 * (or the focus window, if hDeviceWindow is NULL) is taken.
1362 **********************/
1364 if (pPresentationParameters->Windowed &&
1365 ((pPresentationParameters->BackBufferWidth == 0) ||
1366 (pPresentationParameters->BackBufferHeight == 0))) {
1369 GetClientRect(object->win_handle, &Rect);
1371 if (pPresentationParameters->BackBufferWidth == 0) {
1372 pPresentationParameters->BackBufferWidth = Rect.right;
1373 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1375 if (pPresentationParameters->BackBufferHeight == 0) {
1376 pPresentationParameters->BackBufferHeight = Rect.bottom;
1377 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1381 /* Put the correct figures in the presentation parameters */
1382 TRACE("Copying across presentation parameters\n");
1383 object->presentParms = *pPresentationParameters;
1385 TRACE("calling rendertarget CB\n");
1386 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1388 object->presentParms.BackBufferWidth,
1389 object->presentParms.BackBufferHeight,
1390 object->presentParms.BackBufferFormat,
1391 object->presentParms.MultiSampleType,
1392 object->presentParms.MultiSampleQuality,
1393 TRUE /* Lockable */,
1394 &object->frontBuffer,
1395 NULL /* pShared (always null)*/);
1396 if (object->frontBuffer != NULL) {
1397 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1399 ERR("Failed to create the front buffer\n");
1404 * Create an opengl context for the display visual
1405 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1406 * use different properties after that point in time. FIXME: How to handle when requested format
1407 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1408 * it chooses is identical to the one already being used!
1409 **********************************/
1411 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1413 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1416 if (!object->context) {
1417 ERR("Failed to create a new context\n");
1418 hr = WINED3DERR_NOTAVAILABLE;
1421 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1422 object->win_handle, object->context->glCtx, object->win);
1425 /*********************
1426 * Windowed / Fullscreen
1427 *******************/
1430 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1431 * so we should really check to see if there is a fullscreen swapchain already
1432 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1433 **************************************/
1435 if (!pPresentationParameters->Windowed) {
1442 /* Get info on the current display setup */
1444 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1447 /* Change the display settings */
1448 memset(&devmode, 0, sizeof(DEVMODEW));
1449 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1450 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1451 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1452 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1453 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1454 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1456 /* For GetDisplayMode */
1457 This->ddraw_width = devmode.dmPelsWidth;
1458 This->ddraw_height = devmode.dmPelsHeight;
1459 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1461 IWineD3DDevice_SetFullscreen(iface, TRUE);
1463 /* And finally clip mouse to our screen */
1464 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1465 ClipCursor(&clip_rc);
1468 /*********************
1469 * Create the back, front and stencil buffers
1470 *******************/
1471 if(object->presentParms.BackBufferCount > 0) {
1474 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1475 if(!object->backBuffer) {
1476 ERR("Out of memory\n");
1481 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1482 TRACE("calling rendertarget CB\n");
1483 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1485 object->presentParms.BackBufferWidth,
1486 object->presentParms.BackBufferHeight,
1487 object->presentParms.BackBufferFormat,
1488 object->presentParms.MultiSampleType,
1489 object->presentParms.MultiSampleQuality,
1490 TRUE /* Lockable */,
1491 &object->backBuffer[i],
1492 NULL /* pShared (always null)*/);
1493 if(hr == WINED3D_OK && object->backBuffer[i]) {
1494 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1496 ERR("Cannot create new back buffer\n");
1500 glDrawBuffer(GL_BACK);
1501 checkGLcall("glDrawBuffer(GL_BACK)");
1505 object->backBuffer = NULL;
1507 /* Single buffering - draw to front buffer */
1509 glDrawBuffer(GL_FRONT);
1510 checkGLcall("glDrawBuffer(GL_FRONT)");
1514 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1515 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1516 TRACE("Creating depth stencil buffer\n");
1517 if (This->depthStencilBuffer == NULL ) {
1518 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1520 object->presentParms.BackBufferWidth,
1521 object->presentParms.BackBufferHeight,
1522 object->presentParms.AutoDepthStencilFormat,
1523 object->presentParms.MultiSampleType,
1524 object->presentParms.MultiSampleQuality,
1525 FALSE /* FIXME: Discard */,
1526 &This->depthStencilBuffer,
1527 NULL /* pShared (always null)*/ );
1528 if (This->depthStencilBuffer != NULL)
1529 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1532 /** TODO: A check on width, height and multisample types
1533 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1534 ****************************/
1535 object->wantsDepthStencilBuffer = TRUE;
1537 object->wantsDepthStencilBuffer = FALSE;
1540 TRACE("Created swapchain %p\n", object);
1541 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1545 if (object->backBuffer) {
1547 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1548 if(object->backBuffer[i]) {
1549 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1550 IUnknown_Release(bufferParent); /* once for the get parent */
1551 if (IUnknown_Release(bufferParent) > 0) {
1552 FIXME("(%p) Something's still holding the back buffer\n",This);
1556 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1557 object->backBuffer = NULL;
1559 if(object->context) {
1560 DestroyContext(This, object->context);
1562 if(object->frontBuffer) {
1563 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1564 IUnknown_Release(bufferParent); /* once for the get parent */
1565 if (IUnknown_Release(bufferParent) > 0) {
1566 FIXME("(%p) Something's still holding the front buffer\n",This);
1569 if(object) HeapFree(GetProcessHeap(), 0, object);
1573 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1574 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1576 TRACE("(%p)\n", This);
1578 return This->NumberOfSwapChains;
1581 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1585 if(iSwapChain < This->NumberOfSwapChains) {
1586 *pSwapChain = This->swapchains[iSwapChain];
1587 IWineD3DSwapChain_AddRef(*pSwapChain);
1588 TRACE("(%p) returning %p\n", This, *pSwapChain);
1591 TRACE("Swapchain out of range\n");
1593 return WINED3DERR_INVALIDCALL;
1598 * Vertex Declaration
1600 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1601 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1603 IWineD3DVertexDeclarationImpl *object = NULL;
1604 HRESULT hr = WINED3D_OK;
1606 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1607 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1609 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1612 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1617 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1618 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1620 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1621 HRESULT hr = WINED3D_OK;
1622 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1623 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1625 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1627 if (vertex_declaration) {
1628 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1631 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1633 if (WINED3D_OK != hr) {
1634 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1635 IWineD3DVertexShader_Release(*ppVertexShader);
1636 return WINED3DERR_INVALIDCALL;
1642 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1644 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1645 HRESULT hr = WINED3D_OK;
1647 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1648 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1649 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1650 if (WINED3D_OK == hr) {
1651 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1653 WARN("(%p) : Failed to create pixel shader\n", This);
1659 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1661 IWineD3DPaletteImpl *object;
1663 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1665 /* Create the new object */
1666 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1668 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1669 return E_OUTOFMEMORY;
1672 object->lpVtbl = &IWineD3DPalette_Vtbl;
1674 object->Flags = Flags;
1675 object->parent = Parent;
1676 object->wineD3DDevice = This;
1677 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1679 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1682 HeapFree( GetProcessHeap(), 0, object);
1683 return E_OUTOFMEMORY;
1686 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1688 IWineD3DPalette_Release((IWineD3DPalette *) object);
1692 *Palette = (IWineD3DPalette *) object;
1697 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1699 IWineD3DSwapChainImpl *swapchain;
1702 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1703 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1705 /* TODO: Test if OpenGL is compiled in and loaded */
1707 /* Initialize the texture unit mapping to a 1:1 mapping */
1708 for(state = 0; state < MAX_SAMPLERS; state++) {
1709 This->texUnitMap[state] = state;
1711 This->oneToOneTexUnitMap = TRUE;
1713 /* Setup the implicit swapchain */
1714 TRACE("Creating implicit swapchain\n");
1715 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1716 WARN("Failed to create implicit swapchain\n");
1717 return WINED3DERR_INVALIDCALL;
1720 This->NumberOfSwapChains = 1;
1721 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1722 if(!This->swapchains) {
1723 ERR("Out of memory!\n");
1724 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1725 return E_OUTOFMEMORY;
1727 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1729 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1731 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1732 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1733 This->render_targets[0] = swapchain->backBuffer[0];
1734 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1737 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1738 This->render_targets[0] = swapchain->frontBuffer;
1739 This->lastActiveRenderTarget = swapchain->frontBuffer;
1741 IWineD3DSurface_AddRef(This->render_targets[0]);
1742 This->activeContext = swapchain->context;
1744 /* Depth Stencil support */
1745 This->stencilBufferTarget = This->depthStencilBuffer;
1746 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1747 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1749 if (NULL != This->stencilBufferTarget) {
1750 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1753 /* Set up some starting GL setup */
1756 * Initialize openGL extension related variables
1757 * with Default values
1760 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1761 /* Setup all the devices defaults */
1762 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1764 IWineD3DImpl_CheckGraphicsMemory();
1767 /* Initialize our list of GLSL programs */
1768 list_init(&This->glsl_shader_progs);
1770 { /* Set a default viewport */
1774 vp.Width = pPresentationParameters->BackBufferWidth;
1775 vp.Height = pPresentationParameters->BackBufferHeight;
1778 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1781 /* Initialize the current view state */
1782 This->view_ident = 1;
1783 This->contexts[0]->last_was_rhw = 0;
1784 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1785 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1786 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1789 /* Clear the screen */
1790 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1792 This->d3d_initialized = TRUE;
1796 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1800 TRACE("(%p)\n", This);
1802 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1804 /* Delete the pbuffer context if there is any */
1805 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1807 /* Delete the mouse cursor texture */
1808 if(This->cursorTexture) {
1810 glDeleteTextures(1, &This->cursorTexture);
1812 This->cursorTexture = 0;
1815 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1816 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1819 /* Release the buffers (with sanity checks)*/
1820 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1821 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1822 if(This->depthStencilBuffer != This->stencilBufferTarget)
1823 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1825 This->stencilBufferTarget = NULL;
1827 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1828 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1829 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1831 TRACE("Setting rendertarget to NULL\n");
1832 This->render_targets[0] = NULL;
1834 if (This->depthStencilBuffer) {
1835 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1836 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1838 This->depthStencilBuffer = NULL;
1841 for(i=0; i < This->NumberOfSwapChains; i++) {
1842 TRACE("Releasing the implicit swapchain %d\n", i);
1843 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1844 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1848 HeapFree(GetProcessHeap(), 0, This->swapchains);
1849 This->swapchains = NULL;
1850 This->NumberOfSwapChains = 0;
1852 This->d3d_initialized = FALSE;
1856 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1858 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1860 /* Setup the window for fullscreen mode */
1861 if(fullscreen && !This->ddraw_fullscreen) {
1862 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1863 } else if(!fullscreen && This->ddraw_fullscreen) {
1864 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1867 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1868 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1869 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1872 This->ddraw_fullscreen = fullscreen;
1875 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1882 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1884 /* Resize the screen even without a window:
1885 * The app could have unset it with SetCooperativeLevel, but not called
1886 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1887 * but we don't have any hwnd
1890 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1891 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1892 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1893 devmode.dmPelsWidth = pMode->Width;
1894 devmode.dmPelsHeight = pMode->Height;
1896 devmode.dmDisplayFrequency = pMode->RefreshRate;
1897 if (pMode->RefreshRate != 0) {
1898 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1901 /* Only change the mode if necessary */
1902 if( (This->ddraw_width == pMode->Width) &&
1903 (This->ddraw_height == pMode->Height) &&
1904 (This->ddraw_format == pMode->Format) &&
1905 (pMode->RefreshRate == 0) ) {
1909 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1910 if (ret != DISP_CHANGE_SUCCESSFUL) {
1911 if(devmode.dmDisplayFrequency != 0) {
1912 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1913 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1914 devmode.dmDisplayFrequency = 0;
1915 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1917 if(ret != DISP_CHANGE_SUCCESSFUL) {
1918 return DDERR_INVALIDMODE;
1922 /* Store the new values */
1923 This->ddraw_width = pMode->Width;
1924 This->ddraw_height = pMode->Height;
1925 This->ddraw_format = pMode->Format;
1927 /* Only do this with a window of course */
1928 if(This->ddraw_window)
1929 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1931 /* And finally clip mouse to our screen */
1932 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1933 ClipCursor(&clip_rc);
1938 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1940 *ppD3D= This->wineD3D;
1941 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1942 IWineD3D_AddRef(*ppD3D);
1946 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1947 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1948 * into the video ram as possible and seeing how many fit
1949 * you can also get the correct initial value from nvidia and ATI's driver via X
1950 * texture memory is video memory + AGP memory
1951 *******************/
1952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1953 static BOOL showfixmes = TRUE;
1955 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1956 (wined3d_settings.emulated_textureram/(1024*1024)),
1957 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1960 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1961 (wined3d_settings.emulated_textureram/(1024*1024)),
1962 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1963 /* return simulated texture memory left */
1964 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1972 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1975 /* Update the current state block */
1976 This->updateStateBlock->changed.fvf = TRUE;
1977 This->updateStateBlock->set.fvf = TRUE;
1979 if(This->updateStateBlock->fvf == fvf) {
1980 TRACE("Application is setting the old fvf over, nothing to do\n");
1984 This->updateStateBlock->fvf = fvf;
1985 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1991 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1993 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1994 *pfvf = This->stateBlock->fvf;
1999 * Get / Set Stream Source
2001 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2003 IWineD3DVertexBuffer *oldSrc;
2005 if (StreamNumber >= MAX_STREAMS) {
2006 WARN("Stream out of range %d\n", StreamNumber);
2007 return WINED3DERR_INVALIDCALL;
2010 oldSrc = This->stateBlock->streamSource[StreamNumber];
2011 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2013 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2014 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2016 if(oldSrc == pStreamData &&
2017 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2018 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2019 TRACE("Application is setting the old values over, nothing to do\n");
2023 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2025 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2026 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2029 /* Handle recording of state blocks */
2030 if (This->isRecordingState) {
2031 TRACE("Recording... not performing anything\n");
2035 /* Need to do a getParent and pass the reffs up */
2036 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2037 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2038 so for now, just count internally */
2039 if (pStreamData != NULL) {
2040 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2041 InterlockedIncrement(&vbImpl->bindCount);
2043 if (oldSrc != NULL) {
2044 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2052 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2055 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2056 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2058 if (StreamNumber >= MAX_STREAMS) {
2059 WARN("Stream out of range %d\n", StreamNumber);
2060 return WINED3DERR_INVALIDCALL;
2062 *pStream = This->stateBlock->streamSource[StreamNumber];
2063 *pStride = This->stateBlock->streamStride[StreamNumber];
2065 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2068 if (*pStream != NULL) {
2069 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2074 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2076 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2077 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2079 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2080 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2082 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2083 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2084 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2086 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2087 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2094 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2097 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2098 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2100 TRACE("(%p) : returning %d\n", This, *Divider);
2106 * Get / Set & Multiply Transform
2108 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2111 /* Most of this routine, comments included copied from ddraw tree initially: */
2112 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2114 /* Handle recording of state blocks */
2115 if (This->isRecordingState) {
2116 TRACE("Recording... not performing anything\n");
2117 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2118 This->updateStateBlock->set.transform[d3dts] = TRUE;
2119 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2124 * If the new matrix is the same as the current one,
2125 * we cut off any further processing. this seems to be a reasonable
2126 * optimization because as was noticed, some apps (warcraft3 for example)
2127 * tend towards setting the same matrix repeatedly for some reason.
2129 * From here on we assume that the new matrix is different, wherever it matters.
2131 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2132 TRACE("The app is setting the same matrix over again\n");
2135 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2139 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2140 where ViewMat = Camera space, WorldMat = world space.
2142 In OpenGL, camera and world space is combined into GL_MODELVIEW
2143 matrix. The Projection matrix stay projection matrix.
2146 /* Capture the times we can just ignore the change for now */
2147 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2148 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2149 /* Handled by the state manager */
2152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2156 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2158 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2159 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2163 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2164 WINED3DMATRIX *mat = NULL;
2167 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2168 * below means it will be recorded in a state block change, but it
2169 * works regardless where it is recorded.
2170 * If this is found to be wrong, change to StateBlock.
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2173 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2175 if (State < HIGHEST_TRANSFORMSTATE)
2177 mat = &This->updateStateBlock->transforms[State];
2179 FIXME("Unhandled transform state!!\n");
2182 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2184 /* Apply change via set transform - will reapply to eg. lights this way */
2185 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2191 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2192 you can reference any indexes you want as long as that number max are enabled at any
2193 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2194 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2195 but when recording, just build a chain pretty much of commands to be replayed. */
2197 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2199 PLIGHTINFOEL *object = NULL;
2200 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2204 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2206 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2210 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2211 return WINED3DERR_INVALIDCALL;
2214 switch(pLight->Type) {
2215 case WINED3DLIGHT_POINT:
2216 case WINED3DLIGHT_SPOT:
2217 case WINED3DLIGHT_PARALLELPOINT:
2218 case WINED3DLIGHT_GLSPOT:
2219 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2222 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2223 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2224 return WINED3DERR_INVALIDCALL;
2228 case WINED3DLIGHT_DIRECTIONAL:
2229 /* Ignores attenuation */
2233 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2234 return WINED3DERR_INVALIDCALL;
2237 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2238 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2239 if(object->OriginalIndex == Index) break;
2244 TRACE("Adding new light\n");
2245 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2247 ERR("Out of memory error when allocating a light\n");
2248 return E_OUTOFMEMORY;
2250 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2251 object->glIndex = -1;
2252 object->OriginalIndex = Index;
2253 object->changed = TRUE;
2256 /* Initialize the object */
2257 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,
2258 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2259 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2260 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2261 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2262 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2263 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2265 /* Save away the information */
2266 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2268 switch (pLight->Type) {
2269 case WINED3DLIGHT_POINT:
2271 object->lightPosn[0] = pLight->Position.x;
2272 object->lightPosn[1] = pLight->Position.y;
2273 object->lightPosn[2] = pLight->Position.z;
2274 object->lightPosn[3] = 1.0f;
2275 object->cutoff = 180.0f;
2279 case WINED3DLIGHT_DIRECTIONAL:
2281 object->lightPosn[0] = -pLight->Direction.x;
2282 object->lightPosn[1] = -pLight->Direction.y;
2283 object->lightPosn[2] = -pLight->Direction.z;
2284 object->lightPosn[3] = 0.0;
2285 object->exponent = 0.0f;
2286 object->cutoff = 180.0f;
2289 case WINED3DLIGHT_SPOT:
2291 object->lightPosn[0] = pLight->Position.x;
2292 object->lightPosn[1] = pLight->Position.y;
2293 object->lightPosn[2] = pLight->Position.z;
2294 object->lightPosn[3] = 1.0;
2297 object->lightDirn[0] = pLight->Direction.x;
2298 object->lightDirn[1] = pLight->Direction.y;
2299 object->lightDirn[2] = pLight->Direction.z;
2300 object->lightDirn[3] = 1.0;
2303 * opengl-ish and d3d-ish spot lights use too different models for the
2304 * light "intensity" as a function of the angle towards the main light direction,
2305 * so we only can approximate very roughly.
2306 * however spot lights are rather rarely used in games (if ever used at all).
2307 * furthermore if still used, probably nobody pays attention to such details.
2309 if (pLight->Falloff == 0) {
2312 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2314 if (rho < 0.0001) rho = 0.0001f;
2315 object->exponent = -0.3/log(cos(rho/2));
2316 if (object->exponent > 128.0) {
2317 object->exponent = 128.0;
2319 object->cutoff = pLight->Phi*90/M_PI;
2325 FIXME("Unrecognized light type %d\n", pLight->Type);
2328 /* Update the live definitions if the light is currently assigned a glIndex */
2329 if (object->glIndex != -1 && !This->isRecordingState) {
2330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2335 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2336 PLIGHTINFOEL *lightInfo = NULL;
2337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2338 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2340 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2342 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2343 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2344 if(lightInfo->OriginalIndex == Index) break;
2348 if (lightInfo == NULL) {
2349 TRACE("Light information requested but light not defined\n");
2350 return WINED3DERR_INVALIDCALL;
2353 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2358 * Get / Set Light Enable
2359 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2361 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2362 PLIGHTINFOEL *lightInfo = NULL;
2363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2364 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2366 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2368 /* Tests show true = 128...not clear why */
2369 Enable = Enable? 128: 0;
2371 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2372 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2373 if(lightInfo->OriginalIndex == Index) break;
2376 TRACE("Found light: %p\n", lightInfo);
2378 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2379 if (lightInfo == NULL) {
2381 TRACE("Light enabled requested but light not defined, so defining one!\n");
2382 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2384 /* Search for it again! Should be fairly quick as near head of list */
2385 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2386 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2387 if(lightInfo->OriginalIndex == Index) break;
2390 if (lightInfo == NULL) {
2391 FIXME("Adding default lights has failed dismally\n");
2392 return WINED3DERR_INVALIDCALL;
2396 lightInfo->enabledChanged = TRUE;
2398 if(lightInfo->glIndex != -1) {
2399 if(!This->isRecordingState) {
2400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2403 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2404 lightInfo->glIndex = -1;
2406 TRACE("Light already disabled, nothing to do\n");
2409 if (lightInfo->glIndex != -1) {
2411 TRACE("Nothing to do as light was enabled\n");
2414 /* Find a free gl light */
2415 for(i = 0; i < This->maxConcurrentLights; i++) {
2416 if(This->stateBlock->activeLights[i] == NULL) {
2417 This->stateBlock->activeLights[i] = lightInfo;
2418 lightInfo->glIndex = i;
2422 if(lightInfo->glIndex == -1) {
2423 ERR("Too many concurrently active lights\n");
2424 return WINED3DERR_INVALIDCALL;
2427 /* i == lightInfo->glIndex */
2428 if(!This->isRecordingState) {
2429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2437 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2439 PLIGHTINFOEL *lightInfo = NULL;
2440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2443 TRACE("(%p) : for idx(%d)\n", This, Index);
2445 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2446 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2447 if(lightInfo->OriginalIndex == Index) break;
2451 if (lightInfo == NULL) {
2452 TRACE("Light enabled state requested but light not defined\n");
2453 return WINED3DERR_INVALIDCALL;
2455 /* true is 128 according to SetLightEnable */
2456 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2461 * Get / Set Clip Planes
2463 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2467 /* Validate Index */
2468 if (Index >= GL_LIMITS(clipplanes)) {
2469 TRACE("Application has requested clipplane this device doesn't support\n");
2470 return WINED3DERR_INVALIDCALL;
2473 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2474 This->updateStateBlock->set.clipplane[Index] = TRUE;
2475 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2476 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2477 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2478 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2480 /* Handle recording of state blocks */
2481 if (This->isRecordingState) {
2482 TRACE("Recording... not performing anything\n");
2490 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2491 glMatrixMode(GL_MODELVIEW);
2493 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2495 TRACE("Clipplane [%f,%f,%f,%f]\n",
2496 This->updateStateBlock->clipplane[Index][0],
2497 This->updateStateBlock->clipplane[Index][1],
2498 This->updateStateBlock->clipplane[Index][2],
2499 This->updateStateBlock->clipplane[Index][3]);
2500 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2501 checkGLcall("glClipPlane");
2509 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 TRACE("(%p) : for idx %d\n", This, Index);
2513 /* Validate Index */
2514 if (Index >= GL_LIMITS(clipplanes)) {
2515 TRACE("Application has requested clipplane this device doesn't support\n");
2516 return WINED3DERR_INVALIDCALL;
2519 pPlane[0] = This->stateBlock->clipplane[Index][0];
2520 pPlane[1] = This->stateBlock->clipplane[Index][1];
2521 pPlane[2] = This->stateBlock->clipplane[Index][2];
2522 pPlane[3] = This->stateBlock->clipplane[Index][3];
2527 * Get / Set Clip Plane Status
2528 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2530 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 FIXME("(%p) : stub\n", This);
2533 if (NULL == pClipStatus) {
2534 return WINED3DERR_INVALIDCALL;
2536 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2537 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2541 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2543 FIXME("(%p) : stub\n", This);
2544 if (NULL == pClipStatus) {
2545 return WINED3DERR_INVALIDCALL;
2547 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2548 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2553 * Get / Set Material
2555 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 This->updateStateBlock->changed.material = TRUE;
2559 This->updateStateBlock->set.material = TRUE;
2560 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2562 /* Handle recording of state blocks */
2563 if (This->isRecordingState) {
2564 TRACE("Recording... not performing anything\n");
2569 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2570 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2571 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2572 pMaterial->Ambient.b, pMaterial->Ambient.a);
2573 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2574 pMaterial->Specular.b, pMaterial->Specular.a);
2575 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2576 pMaterial->Emissive.b, pMaterial->Emissive.a);
2577 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2579 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2580 checkGLcall("glMaterialfv(GL_AMBIENT)");
2581 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2582 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2584 /* Only change material color if specular is enabled, otherwise it is set to black */
2585 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2586 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2587 checkGLcall("glMaterialfv(GL_SPECULAR");
2589 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2590 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2591 checkGLcall("glMaterialfv(GL_SPECULAR");
2593 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2594 checkGLcall("glMaterialfv(GL_EMISSION)");
2595 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2596 checkGLcall("glMaterialf(GL_SHININESS");
2602 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2605 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2606 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2607 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2608 pMaterial->Ambient.b, pMaterial->Ambient.a);
2609 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2610 pMaterial->Specular.b, pMaterial->Specular.a);
2611 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2612 pMaterial->Emissive.b, pMaterial->Emissive.a);
2613 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2621 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2622 UINT BaseVertexIndex) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2624 IWineD3DIndexBuffer *oldIdxs;
2625 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2627 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2628 oldIdxs = This->updateStateBlock->pIndexData;
2630 This->updateStateBlock->changed.indices = TRUE;
2631 This->updateStateBlock->set.indices = TRUE;
2632 This->updateStateBlock->pIndexData = pIndexData;
2633 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2635 /* Handle recording of state blocks */
2636 if (This->isRecordingState) {
2637 TRACE("Recording... not performing anything\n");
2641 /* The base vertex index affects the stream sources, while
2642 * The index buffer is a seperate index buffer state
2644 if(BaseVertexIndex != oldBaseIndex) {
2645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2647 if(oldIdxs != pIndexData) {
2648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2653 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 *ppIndexData = This->stateBlock->pIndexData;
2658 /* up ref count on ppindexdata */
2660 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2661 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2662 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2664 TRACE("(%p) No index data set\n", This);
2666 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2671 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2672 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2674 TRACE("(%p)->(%d)\n", This, BaseIndex);
2676 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2677 TRACE("Application is setting the old value over, nothing to do\n");
2681 This->updateStateBlock->baseVertexIndex = BaseIndex;
2683 if (This->isRecordingState) {
2684 TRACE("Recording... not performing anything\n");
2687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2692 * Get / Set Viewports
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 TRACE("(%p)\n", This);
2698 This->updateStateBlock->changed.viewport = TRUE;
2699 This->updateStateBlock->set.viewport = TRUE;
2700 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2702 /* Handle recording of state blocks */
2703 if (This->isRecordingState) {
2704 TRACE("Recording... not performing anything\n");
2708 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2709 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2716 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2718 TRACE("(%p)\n", This);
2719 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2724 * Get / Set Render States
2725 * TODO: Verify against dx9 definitions
2727 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2730 DWORD oldValue = This->stateBlock->renderState[State];
2732 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2734 This->updateStateBlock->changed.renderState[State] = TRUE;
2735 This->updateStateBlock->set.renderState[State] = TRUE;
2736 This->updateStateBlock->renderState[State] = Value;
2738 /* Handle recording of state blocks */
2739 if (This->isRecordingState) {
2740 TRACE("Recording... not performing anything\n");
2744 /* Compared here and not before the assignment to allow proper stateblock recording */
2745 if(Value == oldValue) {
2746 TRACE("Application is setting the old value over, nothing to do\n");
2748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2754 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2756 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2757 *pValue = This->stateBlock->renderState[State];
2762 * Get / Set Sampler States
2763 * TODO: Verify against dx9 definitions
2766 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2771 * SetSampler is designed to allow for more than the standard up to 8 textures
2772 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2773 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2775 * http://developer.nvidia.com/object/General_FAQ.html#t6
2777 * There are two new settings for GForce
2779 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2780 * and the texture one:
2781 * GL_MAX_TEXTURE_COORDS_ARB.
2782 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2785 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2786 debug_d3dsamplerstate(Type), Type, Value);
2787 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2788 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2789 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2791 /* Handle recording of state blocks */
2792 if (This->isRecordingState) {
2793 TRACE("Recording... not performing anything\n");
2797 if(oldValue == Value) {
2798 TRACE("Application is setting the old value over, nothing to do\n");
2802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2807 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 *Value = This->stateBlock->samplerState[Sampler][Type];
2810 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2815 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2818 This->updateStateBlock->set.scissorRect = TRUE;
2819 This->updateStateBlock->changed.scissorRect = TRUE;
2820 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2821 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2824 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2826 if(This->isRecordingState) {
2827 TRACE("Recording... not performing anything\n");
2831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2836 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2839 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2840 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2844 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2846 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2848 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2850 This->updateStateBlock->vertexDecl = pDecl;
2851 This->updateStateBlock->changed.vertexDecl = TRUE;
2852 This->updateStateBlock->set.vertexDecl = TRUE;
2854 if (This->isRecordingState) {
2855 TRACE("Recording... not performing anything\n");
2857 } else if(pDecl == oldDecl) {
2858 /* Checked after the assignment to allow proper stateblock recording */
2859 TRACE("Application is setting the old declaration over, nothing to do\n");
2863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2872 *ppDecl = This->stateBlock->vertexDecl;
2873 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2877 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2879 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2881 This->updateStateBlock->vertexShader = pShader;
2882 This->updateStateBlock->changed.vertexShader = TRUE;
2883 This->updateStateBlock->set.vertexShader = TRUE;
2885 if (This->isRecordingState) {
2886 TRACE("Recording... not performing anything\n");
2888 } else if(oldShader == pShader) {
2889 /* Checked here to allow proper stateblock recording */
2890 TRACE("App is setting the old shader over, nothing to do\n");
2894 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 if (NULL == ppShader) {
2905 return WINED3DERR_INVALIDCALL;
2907 *ppShader = This->stateBlock->vertexShader;
2908 if( NULL != *ppShader)
2909 IWineD3DVertexShader_AddRef(*ppShader);
2911 TRACE("(%p) : returning %p\n", This, *ppShader);
2915 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2916 IWineD3DDevice *iface,
2918 CONST BOOL *srcData,
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 int i, cnt = min(count, MAX_CONST_B - start);
2924 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2925 iface, srcData, start, count);
2927 if (srcData == NULL || cnt < 0)
2928 return WINED3DERR_INVALIDCALL;
2930 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2931 for (i = 0; i < cnt; i++)
2932 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2934 for (i = start; i < cnt + start; ++i) {
2935 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2936 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2944 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2945 IWineD3DDevice *iface,
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 int cnt = min(count, MAX_CONST_B - start);
2953 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2954 iface, dstData, start, count);
2956 if (dstData == NULL || cnt < 0)
2957 return WINED3DERR_INVALIDCALL;
2959 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2963 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2964 IWineD3DDevice *iface,
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 int i, cnt = min(count, MAX_CONST_I - start);
2972 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2973 iface, srcData, start, count);
2975 if (srcData == NULL || cnt < 0)
2976 return WINED3DERR_INVALIDCALL;
2978 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2979 for (i = 0; i < cnt; i++)
2980 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2981 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2983 for (i = start; i < cnt + start; ++i) {
2984 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2985 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2994 IWineD3DDevice *iface,
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 int cnt = min(count, MAX_CONST_I - start);
3002 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3003 iface, dstData, start, count);
3005 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3006 return WINED3DERR_INVALIDCALL;
3008 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3012 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3013 IWineD3DDevice *iface,
3015 CONST float *srcData,
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3022 iface, srcData, start, count);
3024 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3025 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3026 return WINED3DERR_INVALIDCALL;
3028 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3030 for (i = 0; i < count; i++)
3031 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3032 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3035 for (i = start; i < count + start; ++i) {
3036 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3037 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3039 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3040 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3042 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3050 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3051 IWineD3DDevice *iface,
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3059 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3060 iface, dstData, start, count);
3062 if (dstData == NULL || cnt < 0)
3063 return WINED3DERR_INVALIDCALL;
3065 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3069 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3071 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3076 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3078 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3079 * it is never called.
3082 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3083 * that would be really messy and require shader recompilation
3084 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3085 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3086 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3087 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3089 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3090 if(This->oneToOneTexUnitMap) {
3091 TRACE("Not touching 1:1 map\n");
3094 TRACE("Restoring 1:1 texture unit mapping\n");
3095 /* Restore a 1:1 mapping */
3096 for(i = 0; i < MAX_SAMPLERS; i++) {
3097 if(This->texUnitMap[i] != i) {
3098 This->texUnitMap[i] = i;
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3100 markTextureStagesDirty(This, i);
3103 This->oneToOneTexUnitMap = TRUE;
3106 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3107 * First, see if we can succeed at all
3110 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3111 if(This->stateBlock->textures[i] == NULL) tex++;
3114 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3115 FIXME("Too many bound textures to support the combiner settings\n");
3119 /* Now work out the mapping */
3121 This->oneToOneTexUnitMap = FALSE;
3122 WARN("Non 1:1 mapping UNTESTED!\n");
3123 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3124 /* Skip NULL textures */
3125 if (!This->stateBlock->textures[i]) {
3126 /* Map to -1, so the check below doesn't fail if a non-NULL
3127 * texture is set on this stage */
3128 TRACE("Mapping texture stage %d to -1\n", i);
3129 This->texUnitMap[i] = -1;
3134 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3135 if(This->texUnitMap[i] != tex) {
3136 This->texUnitMap[i] = tex;
3137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3138 markTextureStagesDirty(This, i);
3146 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3149 This->updateStateBlock->pixelShader = pShader;
3150 This->updateStateBlock->changed.pixelShader = TRUE;
3151 This->updateStateBlock->set.pixelShader = TRUE;
3153 /* Handle recording of state blocks */
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3158 if (This->isRecordingState) {
3159 TRACE("Recording... not performing anything\n");
3163 if(pShader == oldShader) {
3164 TRACE("App is setting the old pixel shader over, nothing to do\n");
3168 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3171 /* Rebuild the texture unit mapping if nvrc's are supported */
3172 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3173 IWineD3DDeviceImpl_FindTexUnitMap(This);
3179 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 if (NULL == ppShader) {
3183 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3184 return WINED3DERR_INVALIDCALL;
3187 *ppShader = This->stateBlock->pixelShader;
3188 if (NULL != *ppShader) {
3189 IWineD3DPixelShader_AddRef(*ppShader);
3191 TRACE("(%p) : returning %p\n", This, *ppShader);
3195 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3196 IWineD3DDevice *iface,
3198 CONST BOOL *srcData,
3201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 int i, cnt = min(count, MAX_CONST_B - start);
3204 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3205 iface, srcData, start, count);
3207 if (srcData == NULL || cnt < 0)
3208 return WINED3DERR_INVALIDCALL;
3210 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3211 for (i = 0; i < cnt; i++)
3212 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3214 for (i = start; i < cnt + start; ++i) {
3215 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3216 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3224 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3225 IWineD3DDevice *iface,
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 int cnt = min(count, MAX_CONST_B - start);
3233 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3234 iface, dstData, start, count);
3236 if (dstData == NULL || cnt < 0)
3237 return WINED3DERR_INVALIDCALL;
3239 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3243 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3244 IWineD3DDevice *iface,
3249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3250 int i, cnt = min(count, MAX_CONST_I - start);
3252 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3253 iface, srcData, start, count);
3255 if (srcData == NULL || cnt < 0)
3256 return WINED3DERR_INVALIDCALL;
3258 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3259 for (i = 0; i < cnt; i++)
3260 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3261 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3263 for (i = start; i < cnt + start; ++i) {
3264 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3265 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3273 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3274 IWineD3DDevice *iface,
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 int cnt = min(count, MAX_CONST_I - start);
3282 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3283 iface, dstData, start, count);
3285 if (dstData == NULL || cnt < 0)
3286 return WINED3DERR_INVALIDCALL;
3288 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3293 IWineD3DDevice *iface,
3295 CONST float *srcData,
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3302 iface, srcData, start, count);
3304 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3305 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3306 return WINED3DERR_INVALIDCALL;
3308 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3310 for (i = 0; i < count; i++)
3311 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3312 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3315 for (i = start; i < count + start; ++i) {
3316 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3317 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3319 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3320 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3322 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3330 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3331 IWineD3DDevice *iface,
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3337 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3339 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3340 iface, dstData, start, count);
3342 if (dstData == NULL || cnt < 0)
3343 return WINED3DERR_INVALIDCALL;
3345 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3349 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3351 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3352 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3354 DWORD DestFVF = dest->fvf;
3356 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3360 if (SrcFVF & WINED3DFVF_NORMAL) {
3361 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3364 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3365 ERR("Source has no position mask\n");
3366 return WINED3DERR_INVALIDCALL;
3369 /* We might access VBOs from this code, so hold the lock */
3372 if (dest->resource.allocatedMemory == NULL) {
3373 /* This may happen if we do direct locking into a vbo. Unlikely,
3374 * but theoretically possible(ddraw processvertices test)
3376 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3377 if(!dest->resource.allocatedMemory) {
3379 ERR("Out of memory\n");
3380 return E_OUTOFMEMORY;
3384 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3385 checkGLcall("glBindBufferARB");
3386 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3388 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3390 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3391 checkGLcall("glUnmapBufferARB");
3395 /* Get a pointer into the destination vbo(create one if none exists) and
3396 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3398 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3403 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3404 if(!dest_conv_addr) {
3405 ERR("Out of memory\n");
3406 /* Continue without storing converted vertices */
3408 dest_conv = dest_conv_addr;
3412 * a) WINED3DRS_CLIPPING is enabled
3413 * b) WINED3DVOP_CLIP is passed
3415 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3416 static BOOL warned = FALSE;
3418 * The clipping code is not quite correct. Some things need
3419 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3420 * so disable clipping for now.
3421 * (The graphics in Half-Life are broken, and my processvertices
3422 * test crashes with IDirect3DDevice3)
3428 FIXME("Clipping is broken and disabled for now\n");
3430 } else doClip = FALSE;
3431 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3433 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3436 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3437 WINED3DTS_PROJECTION,
3439 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3440 WINED3DTS_WORLDMATRIX(0),
3443 TRACE("View mat:\n");
3444 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);
3445 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);
3446 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);
3447 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);
3449 TRACE("Proj mat:\n");
3450 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);
3451 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);
3452 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);
3453 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);
3455 TRACE("World mat:\n");
3456 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);
3457 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);
3458 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);
3459 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);
3461 /* Get the viewport */
3462 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3463 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3464 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3466 multiply_matrix(&mat,&view_mat,&world_mat);
3467 multiply_matrix(&mat,&proj_mat,&mat);
3469 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3471 for (i = 0; i < dwCount; i+= 1) {
3472 unsigned int tex_index;
3474 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3475 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3476 /* The position first */
3478 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3480 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3482 /* Multiplication with world, view and projection matrix */
3483 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);
3484 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);
3485 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);
3486 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);
3488 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3490 /* WARNING: The following things are taken from d3d7 and were not yet checked
3491 * against d3d8 or d3d9!
3494 /* Clipping conditions: From
3495 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3497 * A vertex is clipped if it does not match the following requirements
3501 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3503 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3504 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3509 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3510 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3513 /* "Normal" viewport transformation (not clipped)
3514 * 1) The values are divided by rhw
3515 * 2) The y axis is negative, so multiply it with -1
3516 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3517 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3518 * 4) Multiply x with Width/2 and add Width/2
3519 * 5) The same for the height
3520 * 6) Add the viewpoint X and Y to the 2D coordinates and
3521 * The minimum Z value to z
3522 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3524 * Well, basically it's simply a linear transformation into viewport
3536 z *= vp.MaxZ - vp.MinZ;
3538 x += vp.Width / 2 + vp.X;
3539 y += vp.Height / 2 + vp.Y;
3544 /* That vertex got clipped
3545 * Contrary to OpenGL it is not dropped completely, it just
3546 * undergoes a different calculation.
3548 TRACE("Vertex got clipped\n");
3555 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3556 * outside of the main vertex buffer memory. That needs some more
3561 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3564 ( (float *) dest_ptr)[0] = x;
3565 ( (float *) dest_ptr)[1] = y;
3566 ( (float *) dest_ptr)[2] = z;
3567 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3569 dest_ptr += 3 * sizeof(float);
3571 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3572 dest_ptr += sizeof(float);
3577 ( (float *) dest_conv)[0] = x * w;
3578 ( (float *) dest_conv)[1] = y * w;
3579 ( (float *) dest_conv)[2] = z * w;
3580 ( (float *) dest_conv)[3] = w;
3582 dest_conv += 3 * sizeof(float);
3584 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3585 dest_conv += sizeof(float);
3589 if (DestFVF & WINED3DFVF_PSIZE) {
3590 dest_ptr += sizeof(DWORD);
3591 if(dest_conv) dest_conv += sizeof(DWORD);
3593 if (DestFVF & WINED3DFVF_NORMAL) {
3595 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3596 /* AFAIK this should go into the lighting information */
3597 FIXME("Didn't expect the destination to have a normal\n");
3598 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3600 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3604 if (DestFVF & WINED3DFVF_DIFFUSE) {
3606 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3608 static BOOL warned = FALSE;
3611 ERR("No diffuse color in source, but destination has one\n");
3615 *( (DWORD *) dest_ptr) = 0xffffffff;
3616 dest_ptr += sizeof(DWORD);
3619 *( (DWORD *) dest_conv) = 0xffffffff;
3620 dest_conv += sizeof(DWORD);
3624 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3626 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3627 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3628 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3629 dest_conv += sizeof(DWORD);
3634 if (DestFVF & WINED3DFVF_SPECULAR) {
3635 /* What's the color value in the feedback buffer? */
3637 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3639 static BOOL warned = FALSE;
3642 ERR("No specular color in source, but destination has one\n");
3646 *( (DWORD *) dest_ptr) = 0xFF000000;
3647 dest_ptr += sizeof(DWORD);
3650 *( (DWORD *) dest_conv) = 0xFF000000;
3651 dest_conv += sizeof(DWORD);
3655 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3657 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3658 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3659 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3660 dest_conv += sizeof(DWORD);
3665 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3667 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3668 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3670 ERR("No source texture, but destination requests one\n");
3671 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3672 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3675 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3677 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3684 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3685 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3686 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3687 dwCount * get_flexible_vertex_size(DestFVF),
3689 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3690 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3697 #undef copy_and_next
3699 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3701 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3702 WineDirect3DVertexStridedData strided;
3703 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3706 WARN("NULL source vertex buffer\n");
3707 return WINED3DERR_INVALIDCALL;
3709 /* We don't need the source vbo because this buffer is only used as
3710 * a source for ProcessVertices. Avoid wasting resources by converting the
3711 * buffer and loading the VBO
3714 TRACE("Releasing the source vbo, it won't be needed\n");
3716 if(!SrcImpl->resource.allocatedMemory) {
3717 /* Rescue the data from the buffer */
3719 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3720 if(!SrcImpl->resource.allocatedMemory) {
3721 ERR("Out of memory\n");
3722 return E_OUTOFMEMORY;
3726 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3727 checkGLcall("glBindBufferARB");
3729 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3731 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3734 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3735 checkGLcall("glUnmapBufferARB");
3740 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3741 checkGLcall("glBindBufferARB");
3742 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3743 checkGLcall("glDeleteBuffersARB");
3749 memset(&strided, 0, sizeof(strided));
3750 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3752 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3756 * Get / Set Texture Stage States
3757 * TODO: Verify against dx9 definitions
3759 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3763 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3765 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3767 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3768 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3769 This->updateStateBlock->textureState[Stage][Type] = Value;
3771 if (This->isRecordingState) {
3772 TRACE("Recording... not performing anything\n");
3776 /* Checked after the assignments to allow proper stateblock recording */
3777 if(oldValue == Value) {
3778 TRACE("App is setting the old value over, nothing to do\n");
3782 if(Stage > This->stateBlock->lowest_disabled_stage &&
3783 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3784 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3785 * Changes in other states are important on disabled stages too
3790 if(Type == WINED3DTSS_COLOROP) {
3793 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3794 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3795 * they have to be disabled
3797 * The current stage is dirtified below.
3799 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3800 TRACE("Additionally dirtifying stage %d\n", i);
3801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3803 This->stateBlock->lowest_disabled_stage = Stage;
3804 TRACE("New lowest disabled: %d\n", Stage);
3805 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3806 /* Previously disabled stage enabled. Stages above it may need enabling
3807 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3808 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3810 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3813 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3814 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3817 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3820 This->stateBlock->lowest_disabled_stage = i;
3821 TRACE("New lowest disabled: %d\n", i);
3823 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3824 /* TODO: Built a stage -> texture unit mapping for register combiners */
3828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3830 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3831 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3832 * will call FindTexUnitMap too.
3834 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3835 IWineD3DDeviceImpl_FindTexUnitMap(This);
3840 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3843 *pValue = This->updateStateBlock->textureState[Stage][Type];
3850 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 IWineD3DBaseTexture *oldTexture;
3855 oldTexture = This->updateStateBlock->textures[Stage];
3856 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3858 #if 0 /* TODO: check so vertex textures */
3859 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3860 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3865 if(pTexture != NULL) {
3866 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3868 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3869 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3870 return WINED3DERR_INVALIDCALL;
3872 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3875 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3876 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3878 This->updateStateBlock->set.textures[Stage] = TRUE;
3879 This->updateStateBlock->changed.textures[Stage] = TRUE;
3880 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3881 This->updateStateBlock->textures[Stage] = pTexture;
3883 /* Handle recording of state blocks */
3884 if (This->isRecordingState) {
3885 TRACE("Recording... not performing anything\n");
3889 if(oldTexture == pTexture) {
3890 TRACE("App is setting the same texture again, nothing to do\n");
3894 /** NOTE: MSDN says that setTexture increases the reference count,
3895 * and the the application nust set the texture back to null (or have a leaky application),
3896 * This means we should pass the refcount up to the parent
3897 *******************************/
3898 if (NULL != This->updateStateBlock->textures[Stage]) {
3899 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3900 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3902 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3903 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3904 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3905 * so the COLOROP and ALPHAOP have to be dirtified.
3907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3910 if(bindCount == 1) {
3911 new->baseTexture.sampler = Stage;
3913 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3917 if (NULL != oldTexture) {
3918 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3919 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3921 IWineD3DBaseTexture_Release(oldTexture);
3922 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3927 if(bindCount && old->baseTexture.sampler == Stage) {
3929 /* Have to do a search for the other sampler(s) where the texture is bound to
3930 * Shouldn't happen as long as apps bind a texture only to one stage
3932 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3933 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3934 if(This->updateStateBlock->textures[i] == oldTexture) {
3935 old->baseTexture.sampler = i;
3942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3944 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3945 * pixel shader is used
3947 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3948 IWineD3DDeviceImpl_FindTexUnitMap(This);
3954 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3958 *ppTexture=This->stateBlock->textures[Stage];
3960 IWineD3DBaseTexture_AddRef(*ppTexture);
3968 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3969 IWineD3DSurface **ppBackBuffer) {
3970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3971 IWineD3DSwapChain *swapChain;
3974 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3976 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3977 if (hr == WINED3D_OK) {
3978 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3979 IWineD3DSwapChain_Release(swapChain);
3981 *ppBackBuffer = NULL;
3986 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3988 WARN("(%p) : stub, calling idirect3d for now\n", This);
3989 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3992 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3994 IWineD3DSwapChain *swapChain;
3997 if(iSwapChain > 0) {
3998 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3999 if (hr == WINED3D_OK) {
4000 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4001 IWineD3DSwapChain_Release(swapChain);
4003 FIXME("(%p) Error getting display mode\n", This);
4006 /* Don't read the real display mode,
4007 but return the stored mode instead. X11 can't change the color
4008 depth, and some apps are pretty angry if they SetDisplayMode from
4009 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4011 Also don't relay to the swapchain because with ddraw it's possible
4012 that there isn't a swapchain at all */
4013 pMode->Width = This->ddraw_width;
4014 pMode->Height = This->ddraw_height;
4015 pMode->Format = This->ddraw_format;
4016 pMode->RefreshRate = 0;
4023 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 TRACE("(%p)->(%p)\n", This, hWnd);
4027 if(This->ddraw_fullscreen) {
4028 if(This->ddraw_window && This->ddraw_window != hWnd) {
4029 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4031 if(hWnd && This->ddraw_window != hWnd) {
4032 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4036 This->ddraw_window = hWnd;
4040 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4042 TRACE("(%p)->(%p)\n", This, hWnd);
4044 *hWnd = This->ddraw_window;
4049 * Stateblock related functions
4052 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4054 IWineD3DStateBlockImpl *object;
4055 HRESULT temp_result;
4058 TRACE("(%p)\n", This);
4060 if (This->isRecordingState) {
4061 return WINED3DERR_INVALIDCALL;
4064 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4065 if (NULL == object ) {
4066 FIXME("(%p)Error allocating memory for stateblock\n", This);
4067 return E_OUTOFMEMORY;
4069 TRACE("(%p) created object %p\n", This, object);
4070 object->wineD3DDevice= This;
4071 /** FIXME: object->parent = parent; **/
4072 object->parent = NULL;
4073 object->blockType = WINED3DSBT_ALL;
4075 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4077 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4078 list_init(&object->lightMap[i]);
4081 temp_result = allocate_shader_constants(object);
4082 if (WINED3D_OK != temp_result)
4085 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4086 This->updateStateBlock = object;
4087 This->isRecordingState = TRUE;
4089 TRACE("(%p) recording stateblock %p\n",This , object);
4093 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4096 if (!This->isRecordingState) {
4097 FIXME("(%p) not recording! returning error\n", This);
4098 *ppStateBlock = NULL;
4099 return WINED3DERR_INVALIDCALL;
4102 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4103 This->isRecordingState = FALSE;
4104 This->updateStateBlock = This->stateBlock;
4105 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4106 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4107 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4112 * Scene related functions
4114 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4115 /* At the moment we have no need for any functionality at the beginning
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 TRACE("(%p)\n", This);
4121 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4122 return WINED3DERR_INVALIDCALL;
4124 This->inScene = TRUE;
4128 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4130 TRACE("(%p)\n", This);
4132 if(!This->inScene) {
4133 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4134 return WINED3DERR_INVALIDCALL;
4138 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4140 checkGLcall("glFlush");
4143 This->inScene = FALSE;
4147 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4148 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4149 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4151 IWineD3DSwapChain *swapChain = NULL;
4153 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4155 TRACE("(%p) Presenting the frame\n", This);
4157 for(i = 0 ; i < swapchains ; i ++) {
4159 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4160 TRACE("presentinng chain %d, %p\n", i, swapChain);
4161 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4162 IWineD3DSwapChain_Release(swapChain);
4168 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4169 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4172 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4173 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4174 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4175 GLbitfield glMask = 0;
4177 CONST WINED3DRECT* curRect;
4179 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4180 Count, pRects, Flags, Z, Stencil);
4185 glEnable(GL_SCISSOR_TEST);
4186 checkGLcall("glEnable GL_SCISSOR_TEST");
4187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4189 glDisable(GL_SCISSOR_TEST);
4190 checkGLcall("glEnable GL_SCISSOR_TEST");
4192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4194 if (Count > 0 && pRects) {
4200 /* Only set the values up once, as they are not changing */
4201 if (Flags & WINED3DCLEAR_STENCIL) {
4202 glClearStencil(Stencil);
4203 checkGLcall("glClearStencil");
4204 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4205 glStencilMask(0xFFFFFFFF);
4208 if (Flags & WINED3DCLEAR_ZBUFFER) {
4209 glDepthMask(GL_TRUE);
4211 checkGLcall("glClearDepth");
4212 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4216 if (Flags & WINED3DCLEAR_TARGET) {
4217 TRACE("Clearing screen with glClear to color %x\n", Color);
4218 glClearColor(D3DCOLOR_R(Color),
4222 checkGLcall("glClearColor");
4224 /* Clear ALL colors! */
4225 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4226 glMask = glMask | GL_COLOR_BUFFER_BIT;
4231 checkGLcall("glClear");
4233 /* Now process each rect in turn */
4234 for (i = 0; i < Count; i++) {
4235 /* Note gl uses lower left, width/height */
4236 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4237 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4238 curRect[i].x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2),
4239 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4241 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4242 * The rectangle is not cleared, no error is returned, but further rectanlges are
4243 * still cleared if they are valid
4245 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4246 TRACE("Rectangle with negative dimensions, ignoring\n");
4250 glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2,
4251 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4252 checkGLcall("glScissor");
4255 checkGLcall("glClear");
4259 /* Restore the old values (why..?) */
4260 if (Flags & WINED3DCLEAR_STENCIL) {
4261 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4263 if (Flags & WINED3DCLEAR_TARGET) {
4264 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4265 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4266 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4267 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4268 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4273 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4274 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4276 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4283 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4284 UINT PrimitiveCount) {
4286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4287 This->stateBlock->streamIsUP = FALSE;
4289 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4290 debug_d3dprimitivetype(PrimitiveType),
4291 StartVertex, PrimitiveCount);
4293 if(This->stateBlock->loadBaseVertexIndex != 0) {
4294 This->stateBlock->loadBaseVertexIndex = 0;
4295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4297 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4298 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4299 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4303 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4304 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4305 WINED3DPRIMITIVETYPE PrimitiveType,
4306 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4310 IWineD3DIndexBuffer *pIB;
4311 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4314 pIB = This->stateBlock->pIndexData;
4315 This->stateBlock->streamIsUP = FALSE;
4316 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4318 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4319 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4320 minIndex, NumVertices, startIndex, primCount);
4322 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4323 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4329 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4330 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4334 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4335 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4340 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4341 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4342 UINT VertexStreamZeroStride) {
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4345 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4346 debug_d3dprimitivetype(PrimitiveType),
4347 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4349 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4350 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4351 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4352 This->stateBlock->streamIsUP = TRUE;
4353 This->stateBlock->loadBaseVertexIndex = 0;
4355 /* TODO: Only mark dirty if drawing from a different UP address */
4356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4358 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4359 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4361 /* MSDN specifies stream zero settings must be set to NULL */
4362 This->stateBlock->streamStride[0] = 0;
4363 This->stateBlock->streamSource[0] = NULL;
4365 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4366 * the new stream sources or use UP drawing again
4371 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4372 UINT MinVertexIndex, UINT NumVertices,
4373 UINT PrimitiveCount, CONST void* pIndexData,
4374 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4375 UINT VertexStreamZeroStride) {
4377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4379 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4380 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4381 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4382 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4384 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4390 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4391 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4392 This->stateBlock->streamIsUP = TRUE;
4393 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4395 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4396 This->stateBlock->baseVertexIndex = 0;
4397 This->stateBlock->loadBaseVertexIndex = 0;
4398 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4402 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4404 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4405 This->stateBlock->streamSource[0] = NULL;
4406 This->stateBlock->streamStride[0] = 0;
4407 This->stateBlock->pIndexData = NULL;
4408 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4409 * SetStreamSource to specify a vertex buffer
4415 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4418 /* Mark the state dirty until we have nicer tracking
4419 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4424 This->stateBlock->baseVertexIndex = 0;
4425 This->up_strided = DrawPrimStrideData;
4426 This->stateBlock->streamIsUP = TRUE;
4427 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4428 This->up_strided = NULL;
4431 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4432 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4434 HRESULT hr = WINED3D_OK;
4435 WINED3DRESOURCETYPE sourceType;
4436 WINED3DRESOURCETYPE destinationType;
4439 /* TODO: think about moving the code into IWineD3DBaseTexture */
4441 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4443 /* verify that the source and destination textures aren't NULL */
4444 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4445 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4446 This, pSourceTexture, pDestinationTexture);
4447 hr = WINED3DERR_INVALIDCALL;
4450 if (pSourceTexture == pDestinationTexture) {
4451 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4452 This, pSourceTexture, pDestinationTexture);
4453 hr = WINED3DERR_INVALIDCALL;
4455 /* Verify that the source and destination textures are the same type */
4456 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4457 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4459 if (sourceType != destinationType) {
4460 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4462 hr = WINED3DERR_INVALIDCALL;
4465 /* check that both textures have the identical numbers of levels */
4466 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4467 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4468 hr = WINED3DERR_INVALIDCALL;
4471 if (WINED3D_OK == hr) {
4473 /* Make sure that the destination texture is loaded */
4474 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4476 /* Update every surface level of the texture */
4477 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4479 switch (sourceType) {
4480 case WINED3DRTYPE_TEXTURE:
4482 IWineD3DSurface *srcSurface;
4483 IWineD3DSurface *destSurface;
4485 for (i = 0 ; i < levels ; ++i) {
4486 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4487 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4488 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4489 IWineD3DSurface_Release(srcSurface);
4490 IWineD3DSurface_Release(destSurface);
4491 if (WINED3D_OK != hr) {
4492 WARN("(%p) : Call to update surface failed\n", This);
4498 case WINED3DRTYPE_CUBETEXTURE:
4500 IWineD3DSurface *srcSurface;
4501 IWineD3DSurface *destSurface;
4502 WINED3DCUBEMAP_FACES faceType;
4504 for (i = 0 ; i < levels ; ++i) {
4505 /* Update each cube face */
4506 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4507 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4508 if (WINED3D_OK != hr) {
4509 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4511 TRACE("Got srcSurface %p\n", srcSurface);
4513 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4514 if (WINED3D_OK != hr) {
4515 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4517 TRACE("Got desrSurface %p\n", destSurface);
4519 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4520 IWineD3DSurface_Release(srcSurface);
4521 IWineD3DSurface_Release(destSurface);
4522 if (WINED3D_OK != hr) {
4523 WARN("(%p) : Call to update surface failed\n", This);
4530 #if 0 /* TODO: Add support for volume textures */
4531 case WINED3DRTYPE_VOLUMETEXTURE:
4533 IWineD3DVolume srcVolume = NULL;
4534 IWineD3DSurface destVolume = NULL;
4536 for (i = 0 ; i < levels ; ++i) {
4537 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4538 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4539 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4540 IWineD3DVolume_Release(srcSurface);
4541 IWineD3DVolume_Release(destSurface);
4542 if (WINED3D_OK != hr) {
4543 WARN("(%p) : Call to update volume failed\n", This);
4551 FIXME("(%p) : Unsupported source and destination type\n", This);
4552 hr = WINED3DERR_INVALIDCALL;
4559 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4560 IWineD3DSwapChain *swapChain;
4562 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4563 if(hr == WINED3D_OK) {
4564 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4565 IWineD3DSwapChain_Release(swapChain);
4570 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 /* return a sensible default */
4574 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4575 FIXME("(%p) : stub\n", This);
4579 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4583 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4584 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4585 return WINED3DERR_INVALIDCALL;
4587 for (j = 0; j < 256; ++j) {
4588 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4589 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4590 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4591 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4593 TRACE("(%p) : returning\n", This);
4597 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4600 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4601 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4602 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4603 return WINED3DERR_INVALIDCALL;
4605 for (j = 0; j < 256; ++j) {
4606 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4607 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4608 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4609 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4611 TRACE("(%p) : returning\n", This);
4615 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4617 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4618 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4619 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4620 return WINED3DERR_INVALIDCALL;
4622 /*TODO: stateblocks */
4623 This->currentPalette = PaletteNumber;
4624 TRACE("(%p) : returning\n", This);
4628 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 if (PaletteNumber == NULL) {
4631 WARN("(%p) : returning Invalid Call\n", This);
4632 return WINED3DERR_INVALIDCALL;
4634 /*TODO: stateblocks */
4635 *PaletteNumber = This->currentPalette;
4636 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4640 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 static BOOL showFixmes = TRUE;
4644 FIXME("(%p) : stub\n", This);
4648 This->softwareVertexProcessing = bSoftware;
4653 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 static BOOL showFixmes = TRUE;
4657 FIXME("(%p) : stub\n", This);
4660 return This->softwareVertexProcessing;
4664 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 IWineD3DSwapChain *swapChain;
4669 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4671 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4672 if(hr == WINED3D_OK){
4673 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4674 IWineD3DSwapChain_Release(swapChain);
4676 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4682 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4684 static BOOL showfixmes = TRUE;
4685 if(nSegments != 0.0f) {
4687 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4694 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4696 static BOOL showfixmes = TRUE;
4698 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4704 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4706 /** TODO: remove casts to IWineD3DSurfaceImpl
4707 * NOTE: move code to surface to accomplish this
4708 ****************************************/
4709 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4710 int srcWidth, srcHeight;
4711 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4712 WINED3DFORMAT destFormat, srcFormat;
4714 int srcLeft, destLeft, destTop;
4715 WINED3DPOOL srcPool, destPool;
4717 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4718 glDescriptor *glDescription = NULL;
4720 WINED3DSURFACE_DESC winedesc;
4722 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4723 memset(&winedesc, 0, sizeof(winedesc));
4724 winedesc.Width = &srcSurfaceWidth;
4725 winedesc.Height = &srcSurfaceHeight;
4726 winedesc.Pool = &srcPool;
4727 winedesc.Format = &srcFormat;
4729 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4731 winedesc.Width = &destSurfaceWidth;
4732 winedesc.Height = &destSurfaceHeight;
4733 winedesc.Pool = &destPool;
4734 winedesc.Format = &destFormat;
4735 winedesc.Size = &destSize;
4737 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4739 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4740 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4741 return WINED3DERR_INVALIDCALL;
4744 if (destFormat == WINED3DFMT_UNKNOWN) {
4745 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4746 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4748 /* Get the update surface description */
4749 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4753 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4754 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4755 checkGLcall("glActiveTextureARB");
4758 /* Make sure the surface is loaded and up to date */
4759 IWineD3DSurface_PreLoad(pDestinationSurface);
4761 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4763 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4764 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4765 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4766 srcLeft = pSourceRect ? pSourceRect->left : 0;
4767 destLeft = pDestPoint ? pDestPoint->x : 0;
4768 destTop = pDestPoint ? pDestPoint->y : 0;
4771 /* This function doesn't support compressed textures
4772 the pitch is just bytesPerPixel * width */
4773 if(srcWidth != srcSurfaceWidth || srcLeft ){
4774 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4775 offset += srcLeft * pSrcSurface->bytesPerPixel;
4776 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4778 /* TODO DXT formats */
4780 if(pSourceRect != NULL && pSourceRect->top != 0){
4781 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4783 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4785 ,glDescription->level
4790 ,glDescription->glFormat
4791 ,glDescription->glType
4792 ,IWineD3DSurface_GetData(pSourceSurface)
4796 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4798 /* need to lock the surface to get the data */
4799 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4802 /* TODO: Cube and volume support */
4804 /* not a whole row so we have to do it a line at a time */
4807 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4808 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4810 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4812 glTexSubImage2D(glDescription->target
4813 ,glDescription->level
4818 ,glDescription->glFormat
4819 ,glDescription->glType
4820 ,data /* could be quicker using */
4825 } else { /* Full width, so just write out the whole texture */
4827 if (WINED3DFMT_DXT1 == destFormat ||
4828 WINED3DFMT_DXT2 == destFormat ||
4829 WINED3DFMT_DXT3 == destFormat ||
4830 WINED3DFMT_DXT4 == destFormat ||
4831 WINED3DFMT_DXT5 == destFormat) {
4832 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4833 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4834 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4835 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4836 } if (destFormat != srcFormat) {
4837 FIXME("Updating mixed format compressed texture is not curretly support\n");
4839 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4840 glDescription->level,
4841 glDescription->glFormatInternal,
4846 IWineD3DSurface_GetData(pSourceSurface));
4849 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4854 glTexSubImage2D(glDescription->target
4855 ,glDescription->level
4860 ,glDescription->glFormat
4861 ,glDescription->glType
4862 ,IWineD3DSurface_GetData(pSourceSurface)
4866 checkGLcall("glTexSubImage2D");
4870 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4876 /* Implementation details at http://developer.nvidia.com/attach/6494
4878 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4879 hmm.. no longer supported use
4880 OpenGL evaluators or tessellate surfaces within your application.
4883 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4884 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4886 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4887 FIXME("(%p) : Stub\n", This);
4892 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4893 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4896 FIXME("(%p) : Stub\n", This);
4900 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4902 TRACE("(%p) Handle(%d)\n", This, Handle);
4903 FIXME("(%p) : Stub\n", This);
4907 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4909 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4911 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4913 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4914 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4915 return WINED3DERR_INVALIDCALL;
4918 /* Just forward this to the DirectDraw blitting engine */
4919 memset(&BltFx, 0, sizeof(BltFx));
4920 BltFx.dwSize = sizeof(BltFx);
4921 BltFx.u5.dwFillColor = color;
4922 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4925 /* rendertarget and deptth stencil functions */
4926 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4929 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4930 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4931 return WINED3DERR_INVALIDCALL;
4934 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4935 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4936 /* Note inc ref on returned surface */
4937 if(*ppRenderTarget != NULL)
4938 IWineD3DSurface_AddRef(*ppRenderTarget);
4942 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4944 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4945 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4946 IWineD3DSwapChainImpl *Swapchain;
4949 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4951 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4952 if(hr != WINED3D_OK) {
4953 ERR("Can't get the swapchain\n");
4957 /* Make sure to release the swapchain */
4958 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4960 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4961 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4962 return WINED3DERR_INVALIDCALL;
4964 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4965 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4966 return WINED3DERR_INVALIDCALL;
4969 if(Swapchain->frontBuffer != Front) {
4970 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4972 if(Swapchain->frontBuffer)
4973 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4974 Swapchain->frontBuffer = Front;
4976 if(Swapchain->frontBuffer) {
4977 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4981 if(Back && !Swapchain->backBuffer) {
4982 /* We need memory for the back buffer array - only one back buffer this way */
4983 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4984 if(!Swapchain->backBuffer) {
4985 ERR("Out of memory\n");
4986 return E_OUTOFMEMORY;
4990 if(Swapchain->backBuffer[0] != Back) {
4991 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4993 if(!Swapchain->backBuffer[0]) {
4994 /* GL was told to draw to the front buffer at creation,
4997 glDrawBuffer(GL_BACK);
4998 checkGLcall("glDrawBuffer(GL_BACK)");
4999 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5000 Swapchain->presentParms.BackBufferCount = 1;
5002 /* That makes problems - disable for now */
5003 /* glDrawBuffer(GL_FRONT); */
5004 checkGLcall("glDrawBuffer(GL_FRONT)");
5005 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5006 Swapchain->presentParms.BackBufferCount = 0;
5010 if(Swapchain->backBuffer[0])
5011 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5012 Swapchain->backBuffer[0] = Back;
5014 if(Swapchain->backBuffer[0]) {
5015 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5017 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5025 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 *ppZStencilSurface = This->depthStencilBuffer;
5028 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5030 if(*ppZStencilSurface != NULL) {
5031 /* Note inc ref on returned surface */
5032 IWineD3DSurface_AddRef(*ppZStencilSurface);
5037 static void bind_fbo(IWineD3DDevice *iface) {
5038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5041 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5042 checkGLcall("glGenFramebuffersEXT()");
5044 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5045 checkGLcall("glBindFramebuffer()");
5048 /* TODO: Handle stencil attachments */
5049 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5051 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5053 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5057 if (depth_stencil_impl) {
5058 GLenum texttarget, target;
5059 GLint old_binding = 0;
5061 IWineD3DSurface_PreLoad(depth_stencil);
5062 texttarget = depth_stencil_impl->glDescription.target;
5063 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5065 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5066 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5067 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5068 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5069 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5070 glBindTexture(target, old_binding);
5072 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5073 checkGLcall("glFramebufferTexture2DEXT()");
5075 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5076 checkGLcall("glFramebufferTexture2DEXT()");
5079 if (!This->render_offscreen) {
5080 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5081 checkGLcall("glBindFramebuffer()");
5085 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5087 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5089 if (idx >= GL_LIMITS(buffers)) {
5090 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5096 GLenum texttarget, target;
5097 GLint old_binding = 0;
5099 IWineD3DSurface_PreLoad(render_target);
5100 texttarget = rtimpl->glDescription.target;
5101 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5103 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5104 glBindTexture(target, rtimpl->glDescription.textureName);
5105 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5106 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5107 glBindTexture(target, old_binding);
5109 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5110 checkGLcall("glFramebufferTexture2DEXT()");
5112 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5114 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5115 checkGLcall("glFramebufferTexture2DEXT()");
5117 This->draw_buffers[idx] = GL_NONE;
5120 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5121 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5122 checkGLcall("glDrawBuffers()");
5125 if (!This->render_offscreen) {
5126 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5127 checkGLcall("glBindFramebuffer()");
5131 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5133 WINED3DVIEWPORT viewport;
5135 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5137 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5138 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5139 return WINED3DERR_INVALIDCALL;
5142 /* MSDN says that null disables the render target
5143 but a device must always be associated with a render target
5144 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5146 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5149 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5150 FIXME("Trying to set render target 0 to NULL\n");
5151 return WINED3DERR_INVALIDCALL;
5153 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5154 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);
5155 return WINED3DERR_INVALIDCALL;
5158 /* If we are trying to set what we already have, don't bother */
5159 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5160 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5163 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5164 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5165 This->render_targets[RenderTargetIndex] = pRenderTarget;
5167 /* Render target 0 is special */
5168 if(RenderTargetIndex == 0) {
5169 /* Finally, reset the viewport as the MSDN states. */
5170 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5171 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5174 viewport.MaxZ = 1.0f;
5175 viewport.MinZ = 0.0f;
5176 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5178 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5180 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5181 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5183 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5185 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5186 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5191 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5193 HRESULT hr = WINED3D_OK;
5194 IWineD3DSurface *tmp;
5196 TRACE("(%p) Swapping z-buffer\n",This);
5198 if (pNewZStencil == This->stencilBufferTarget) {
5199 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5201 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5202 * depending on the renter target implementation being used.
5203 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5204 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5205 * stencil buffer and incure an extra memory overhead
5206 ******************************************************/
5209 tmp = This->stencilBufferTarget;
5210 This->stencilBufferTarget = pNewZStencil;
5211 /* should we be calling the parent or the wined3d surface? */
5212 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5213 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5215 /** TODO: glEnable/glDisable on depth/stencil depending on
5216 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5217 **********************************************************/
5218 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5219 set_depth_stencil_fbo(iface, pNewZStencil);
5226 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5227 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5229 /* TODO: the use of Impl is deprecated. */
5230 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5232 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5234 /* some basic validation checks */
5235 if(This->cursorTexture) {
5237 glDeleteTextures(1, &This->cursorTexture);
5239 This->cursorTexture = 0;
5243 /* MSDN: Cursor must be A8R8G8B8 */
5244 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5245 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5246 return WINED3DERR_INVALIDCALL;
5249 /* MSDN: Cursor must be smaller than the display mode */
5250 if(pSur->currentDesc.Width > This->ddraw_width ||
5251 pSur->currentDesc.Height > This->ddraw_height) {
5252 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);
5253 return WINED3DERR_INVALIDCALL;
5256 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5257 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5258 * Texture and Blitting code to draw the cursor
5260 pSur->Flags |= SFLAG_FORCELOAD;
5261 IWineD3DSurface_PreLoad(pCursorBitmap);
5262 pSur->Flags &= ~SFLAG_FORCELOAD;
5263 /* Do not store the surface's pointer because the application may release
5264 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5265 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5267 This->cursorTexture = pSur->glDescription.textureName;
5268 This->cursorWidth = pSur->currentDesc.Width;
5269 This->cursorHeight = pSur->currentDesc.Height;
5270 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5273 This->xHotSpot = XHotSpot;
5274 This->yHotSpot = YHotSpot;
5278 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5280 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5282 This->xScreenSpace = XScreenSpace;
5283 This->yScreenSpace = YScreenSpace;
5289 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5291 BOOL oldVisible = This->bCursorVisible;
5292 TRACE("(%p) : visible(%d)\n", This, bShow);
5294 if(This->cursorTexture)
5295 This->bCursorVisible = bShow;
5300 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5302 TRACE("(%p) : state (%u)\n", This, This->state);
5303 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5304 switch (This->state) {
5307 case WINED3DERR_DEVICELOST:
5309 ResourceList *resourceList = This->resources;
5310 while (NULL != resourceList) {
5311 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5312 return WINED3DERR_DEVICENOTRESET;
5313 resourceList = resourceList->next;
5315 return WINED3DERR_DEVICELOST;
5317 case WINED3DERR_DRIVERINTERNALERROR:
5318 return WINED3DERR_DRIVERINTERNALERROR;
5322 return WINED3DERR_DRIVERINTERNALERROR;
5326 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5328 /** FIXME: Resource tracking needs to be done,
5329 * The closes we can do to this is set the priorities of all managed textures low
5330 * and then reset them.
5331 ***********************************************************/
5332 FIXME("(%p) : stub\n", This);
5336 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5337 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5339 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5340 if(surface->Flags & SFLAG_DIBSECTION) {
5341 /* Release the DC */
5342 SelectObject(surface->hDC, surface->dib.holdbitmap);
5343 DeleteDC(surface->hDC);
5344 /* Release the DIB section */
5345 DeleteObject(surface->dib.DIBsection);
5346 surface->dib.bitmap_data = NULL;
5347 surface->resource.allocatedMemory = NULL;
5348 surface->Flags &= ~SFLAG_DIBSECTION;
5350 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5351 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5352 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5353 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5354 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5356 surface->pow2Width = surface->pow2Height = 1;
5357 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5358 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5360 if(surface->glDescription.textureName) {
5362 glDeleteTextures(1, &surface->glDescription.textureName);
5364 surface->glDescription.textureName = 0;
5366 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5367 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5368 surface->Flags |= SFLAG_NONPOW2;
5370 surface->Flags &= ~SFLAG_NONPOW2;
5372 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5373 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5376 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5378 IWineD3DSwapChainImpl *swapchain;
5380 BOOL DisplayModeChanged = FALSE;
5381 WINED3DDISPLAYMODE mode;
5382 TRACE("(%p)\n", This);
5384 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5386 ERR("Failed to get the first implicit swapchain\n");
5390 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5391 * on an existing gl context, so there's no real need for recreation.
5393 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5395 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5397 TRACE("New params:\n");
5398 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5399 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5400 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5401 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5402 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5403 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5404 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5405 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5406 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5407 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5408 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5409 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5410 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5412 /* No special treatment of these parameters. Just store them */
5413 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5414 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5415 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5416 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5418 /* What to do about these? */
5419 if(pPresentationParameters->BackBufferCount != 0 &&
5420 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5421 ERR("Cannot change the back buffer count yet\n");
5423 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5424 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5425 ERR("Cannot change the back buffer format yet\n");
5427 if(pPresentationParameters->hDeviceWindow != NULL &&
5428 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5429 ERR("Cannot change the device window yet\n");
5431 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5432 ERR("What do do about a changed auto depth stencil parameter?\n");
5435 if(pPresentationParameters->Windowed) {
5436 mode.Width = swapchain->orig_width;
5437 mode.Height = swapchain->orig_height;
5438 mode.RefreshRate = 0;
5439 mode.Format = swapchain->presentParms.BackBufferFormat;
5441 mode.Width = pPresentationParameters->BackBufferWidth;
5442 mode.Height = pPresentationParameters->BackBufferHeight;
5443 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5444 mode.Format = swapchain->presentParms.BackBufferFormat;
5447 /* Should Width == 800 && Height == 0 set 800x600? */
5448 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5449 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5450 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5457 vp.Width = pPresentationParameters->BackBufferWidth;
5458 vp.Height = pPresentationParameters->BackBufferHeight;
5462 if(!pPresentationParameters->Windowed) {
5463 DisplayModeChanged = TRUE;
5465 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5466 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5468 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5469 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5470 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5473 /* Now set the new viewport */
5474 IWineD3DDevice_SetViewport(iface, &vp);
5477 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5478 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5479 DisplayModeChanged) {
5481 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5482 if(!pPresentationParameters->Windowed) {
5483 IWineD3DDevice_SetFullscreen(iface, TRUE);
5486 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5488 /* Switching out of fullscreen mode? First set the original res, then change the window */
5489 if(pPresentationParameters->Windowed) {
5490 IWineD3DDevice_SetFullscreen(iface, FALSE);
5492 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5495 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5499 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5501 /** FIXME: always true at the moment **/
5502 if(!bEnableDialogs) {
5503 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5509 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5511 TRACE("(%p) : pParameters %p\n", This, pParameters);
5513 *pParameters = This->createParms;
5517 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST 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 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5525 IWineD3DSwapChain_Release(swapchain);
5530 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5531 IWineD3DSwapChain *swapchain;
5532 HRESULT hrc = WINED3D_OK;
5534 TRACE("Relaying to swapchain\n");
5536 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5537 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5538 IWineD3DSwapChain_Release(swapchain);
5544 /** ********************************************************
5545 * Notification functions
5546 ** ********************************************************/
5547 /** This function must be called in the release of a resource when ref == 0,
5548 * the contents of resource must still be correct,
5549 * any handels to other resource held by the caller must be closed
5550 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5551 *****************************************************/
5552 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 ResourceList* resourceList;
5556 TRACE("(%p) : resource %p\n", This, resource);
5558 EnterCriticalSection(&resourceStoreCriticalSection);
5560 /* add a new texture to the frot of the linked list */
5561 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5562 resourceList->resource = resource;
5564 /* Get the old head */
5565 resourceList->next = This->resources;
5567 This->resources = resourceList;
5568 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5571 LeaveCriticalSection(&resourceStoreCriticalSection);
5576 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5578 ResourceList* resourceList = NULL;
5579 ResourceList* previousResourceList = NULL;
5581 TRACE("(%p) : resource %p\n", This, resource);
5584 EnterCriticalSection(&resourceStoreCriticalSection);
5586 resourceList = This->resources;
5588 while (resourceList != NULL) {
5589 if(resourceList->resource == resource) break;
5590 previousResourceList = resourceList;
5591 resourceList = resourceList->next;
5594 if (resourceList == NULL) {
5595 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5597 LeaveCriticalSection(&resourceStoreCriticalSection);
5601 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5603 /* make sure we don't leave a hole in the list */
5604 if (previousResourceList != NULL) {
5605 previousResourceList->next = resourceList->next;
5607 This->resources = resourceList->next;
5611 LeaveCriticalSection(&resourceStoreCriticalSection);
5617 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5621 TRACE("(%p) : resource %p\n", This, resource);
5622 switch(IWineD3DResource_GetType(resource)){
5623 case WINED3DRTYPE_SURFACE:
5624 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5626 case WINED3DRTYPE_TEXTURE:
5627 case WINED3DRTYPE_CUBETEXTURE:
5628 case WINED3DRTYPE_VOLUMETEXTURE:
5629 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5630 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5631 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5632 This->stateBlock->textures[counter] = NULL;
5634 if (This->updateStateBlock != This->stateBlock ){
5635 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5636 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5637 This->updateStateBlock->textures[counter] = NULL;
5642 case WINED3DRTYPE_VOLUME:
5643 /* TODO: nothing really? */
5645 case WINED3DRTYPE_VERTEXBUFFER:
5646 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5649 TRACE("Cleaning up stream pointers\n");
5651 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5652 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5653 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5655 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5656 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5657 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5658 This->updateStateBlock->streamSource[streamNumber] = 0;
5659 /* Set changed flag? */
5662 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) */
5663 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5664 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5665 This->stateBlock->streamSource[streamNumber] = 0;
5668 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5669 else { /* This shouldn't happen */
5670 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5677 case WINED3DRTYPE_INDEXBUFFER:
5678 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5679 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5680 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5681 This->updateStateBlock->pIndexData = NULL;
5684 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5685 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5686 This->stateBlock->pIndexData = NULL;
5692 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5697 /* Remove the resoruce from the resourceStore */
5698 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5700 TRACE("Resource released\n");
5704 /**********************************************************
5705 * IWineD3DDevice VTbl follows
5706 **********************************************************/
5708 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5710 /*** IUnknown methods ***/
5711 IWineD3DDeviceImpl_QueryInterface,
5712 IWineD3DDeviceImpl_AddRef,
5713 IWineD3DDeviceImpl_Release,
5714 /*** IWineD3DDevice methods ***/
5715 IWineD3DDeviceImpl_GetParent,
5716 /*** Creation methods**/
5717 IWineD3DDeviceImpl_CreateVertexBuffer,
5718 IWineD3DDeviceImpl_CreateIndexBuffer,
5719 IWineD3DDeviceImpl_CreateStateBlock,
5720 IWineD3DDeviceImpl_CreateSurface,
5721 IWineD3DDeviceImpl_CreateTexture,
5722 IWineD3DDeviceImpl_CreateVolumeTexture,
5723 IWineD3DDeviceImpl_CreateVolume,
5724 IWineD3DDeviceImpl_CreateCubeTexture,
5725 IWineD3DDeviceImpl_CreateQuery,
5726 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5727 IWineD3DDeviceImpl_CreateVertexDeclaration,
5728 IWineD3DDeviceImpl_CreateVertexShader,
5729 IWineD3DDeviceImpl_CreatePixelShader,
5730 IWineD3DDeviceImpl_CreatePalette,
5731 /*** Odd functions **/
5732 IWineD3DDeviceImpl_Init3D,
5733 IWineD3DDeviceImpl_Uninit3D,
5734 IWineD3DDeviceImpl_SetFullscreen,
5735 IWineD3DDeviceImpl_EvictManagedResources,
5736 IWineD3DDeviceImpl_GetAvailableTextureMem,
5737 IWineD3DDeviceImpl_GetBackBuffer,
5738 IWineD3DDeviceImpl_GetCreationParameters,
5739 IWineD3DDeviceImpl_GetDeviceCaps,
5740 IWineD3DDeviceImpl_GetDirect3D,
5741 IWineD3DDeviceImpl_GetDisplayMode,
5742 IWineD3DDeviceImpl_SetDisplayMode,
5743 IWineD3DDeviceImpl_GetHWND,
5744 IWineD3DDeviceImpl_SetHWND,
5745 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5746 IWineD3DDeviceImpl_GetRasterStatus,
5747 IWineD3DDeviceImpl_GetSwapChain,
5748 IWineD3DDeviceImpl_Reset,
5749 IWineD3DDeviceImpl_SetDialogBoxMode,
5750 IWineD3DDeviceImpl_SetCursorProperties,
5751 IWineD3DDeviceImpl_SetCursorPosition,
5752 IWineD3DDeviceImpl_ShowCursor,
5753 IWineD3DDeviceImpl_TestCooperativeLevel,
5754 /*** Getters and setters **/
5755 IWineD3DDeviceImpl_SetClipPlane,
5756 IWineD3DDeviceImpl_GetClipPlane,
5757 IWineD3DDeviceImpl_SetClipStatus,
5758 IWineD3DDeviceImpl_GetClipStatus,
5759 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5760 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5761 IWineD3DDeviceImpl_SetDepthStencilSurface,
5762 IWineD3DDeviceImpl_GetDepthStencilSurface,
5763 IWineD3DDeviceImpl_SetFVF,
5764 IWineD3DDeviceImpl_GetFVF,
5765 IWineD3DDeviceImpl_SetGammaRamp,
5766 IWineD3DDeviceImpl_GetGammaRamp,
5767 IWineD3DDeviceImpl_SetIndices,
5768 IWineD3DDeviceImpl_GetIndices,
5769 IWineD3DDeviceImpl_SetBasevertexIndex,
5770 IWineD3DDeviceImpl_SetLight,
5771 IWineD3DDeviceImpl_GetLight,
5772 IWineD3DDeviceImpl_SetLightEnable,
5773 IWineD3DDeviceImpl_GetLightEnable,
5774 IWineD3DDeviceImpl_SetMaterial,
5775 IWineD3DDeviceImpl_GetMaterial,
5776 IWineD3DDeviceImpl_SetNPatchMode,
5777 IWineD3DDeviceImpl_GetNPatchMode,
5778 IWineD3DDeviceImpl_SetPaletteEntries,
5779 IWineD3DDeviceImpl_GetPaletteEntries,
5780 IWineD3DDeviceImpl_SetPixelShader,
5781 IWineD3DDeviceImpl_GetPixelShader,
5782 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5783 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5784 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5785 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5786 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5787 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5788 IWineD3DDeviceImpl_SetRenderState,
5789 IWineD3DDeviceImpl_GetRenderState,
5790 IWineD3DDeviceImpl_SetRenderTarget,
5791 IWineD3DDeviceImpl_GetRenderTarget,
5792 IWineD3DDeviceImpl_SetFrontBackBuffers,
5793 IWineD3DDeviceImpl_SetSamplerState,
5794 IWineD3DDeviceImpl_GetSamplerState,
5795 IWineD3DDeviceImpl_SetScissorRect,
5796 IWineD3DDeviceImpl_GetScissorRect,
5797 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5798 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5799 IWineD3DDeviceImpl_SetStreamSource,
5800 IWineD3DDeviceImpl_GetStreamSource,
5801 IWineD3DDeviceImpl_SetStreamSourceFreq,
5802 IWineD3DDeviceImpl_GetStreamSourceFreq,
5803 IWineD3DDeviceImpl_SetTexture,
5804 IWineD3DDeviceImpl_GetTexture,
5805 IWineD3DDeviceImpl_SetTextureStageState,
5806 IWineD3DDeviceImpl_GetTextureStageState,
5807 IWineD3DDeviceImpl_SetTransform,
5808 IWineD3DDeviceImpl_GetTransform,
5809 IWineD3DDeviceImpl_SetVertexDeclaration,
5810 IWineD3DDeviceImpl_GetVertexDeclaration,
5811 IWineD3DDeviceImpl_SetVertexShader,
5812 IWineD3DDeviceImpl_GetVertexShader,
5813 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5814 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5815 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5816 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5817 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5818 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5819 IWineD3DDeviceImpl_SetViewport,
5820 IWineD3DDeviceImpl_GetViewport,
5821 IWineD3DDeviceImpl_MultiplyTransform,
5822 IWineD3DDeviceImpl_ValidateDevice,
5823 IWineD3DDeviceImpl_ProcessVertices,
5824 /*** State block ***/
5825 IWineD3DDeviceImpl_BeginStateBlock,
5826 IWineD3DDeviceImpl_EndStateBlock,
5827 /*** Scene management ***/
5828 IWineD3DDeviceImpl_BeginScene,
5829 IWineD3DDeviceImpl_EndScene,
5830 IWineD3DDeviceImpl_Present,
5831 IWineD3DDeviceImpl_Clear,
5833 IWineD3DDeviceImpl_DrawPrimitive,
5834 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5835 IWineD3DDeviceImpl_DrawPrimitiveUP,
5836 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5837 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5838 IWineD3DDeviceImpl_DrawRectPatch,
5839 IWineD3DDeviceImpl_DrawTriPatch,
5840 IWineD3DDeviceImpl_DeletePatch,
5841 IWineD3DDeviceImpl_ColorFill,
5842 IWineD3DDeviceImpl_UpdateTexture,
5843 IWineD3DDeviceImpl_UpdateSurface,
5844 IWineD3DDeviceImpl_GetFrontBufferData,
5845 /*** object tracking ***/
5846 IWineD3DDeviceImpl_ResourceReleased
5850 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5851 WINED3DRS_ALPHABLENDENABLE ,
5852 WINED3DRS_ALPHAFUNC ,
5853 WINED3DRS_ALPHAREF ,
5854 WINED3DRS_ALPHATESTENABLE ,
5856 WINED3DRS_COLORWRITEENABLE ,
5857 WINED3DRS_DESTBLEND ,
5858 WINED3DRS_DITHERENABLE ,
5859 WINED3DRS_FILLMODE ,
5860 WINED3DRS_FOGDENSITY ,
5862 WINED3DRS_FOGSTART ,
5863 WINED3DRS_LASTPIXEL ,
5864 WINED3DRS_SHADEMODE ,
5865 WINED3DRS_SRCBLEND ,
5866 WINED3DRS_STENCILENABLE ,
5867 WINED3DRS_STENCILFAIL ,
5868 WINED3DRS_STENCILFUNC ,
5869 WINED3DRS_STENCILMASK ,
5870 WINED3DRS_STENCILPASS ,
5871 WINED3DRS_STENCILREF ,
5872 WINED3DRS_STENCILWRITEMASK ,
5873 WINED3DRS_STENCILZFAIL ,
5874 WINED3DRS_TEXTUREFACTOR ,
5885 WINED3DRS_ZWRITEENABLE
5888 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5889 WINED3DTSS_ADDRESSW ,
5890 WINED3DTSS_ALPHAARG0 ,
5891 WINED3DTSS_ALPHAARG1 ,
5892 WINED3DTSS_ALPHAARG2 ,
5893 WINED3DTSS_ALPHAOP ,
5894 WINED3DTSS_BUMPENVLOFFSET ,
5895 WINED3DTSS_BUMPENVLSCALE ,
5896 WINED3DTSS_BUMPENVMAT00 ,
5897 WINED3DTSS_BUMPENVMAT01 ,
5898 WINED3DTSS_BUMPENVMAT10 ,
5899 WINED3DTSS_BUMPENVMAT11 ,
5900 WINED3DTSS_COLORARG0 ,
5901 WINED3DTSS_COLORARG1 ,
5902 WINED3DTSS_COLORARG2 ,
5903 WINED3DTSS_COLOROP ,
5904 WINED3DTSS_RESULTARG ,
5905 WINED3DTSS_TEXCOORDINDEX ,
5906 WINED3DTSS_TEXTURETRANSFORMFLAGS
5909 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5910 WINED3DSAMP_ADDRESSU ,
5911 WINED3DSAMP_ADDRESSV ,
5912 WINED3DSAMP_ADDRESSW ,
5913 WINED3DSAMP_BORDERCOLOR ,
5914 WINED3DSAMP_MAGFILTER ,
5915 WINED3DSAMP_MINFILTER ,
5916 WINED3DSAMP_MIPFILTER ,
5917 WINED3DSAMP_MIPMAPLODBIAS ,
5918 WINED3DSAMP_MAXMIPLEVEL ,
5919 WINED3DSAMP_MAXANISOTROPY ,
5920 WINED3DSAMP_SRGBTEXTURE ,
5921 WINED3DSAMP_ELEMENTINDEX
5924 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5926 WINED3DRS_AMBIENTMATERIALSOURCE ,
5927 WINED3DRS_CLIPPING ,
5928 WINED3DRS_CLIPPLANEENABLE ,
5929 WINED3DRS_COLORVERTEX ,
5930 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5931 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5932 WINED3DRS_FOGDENSITY ,
5934 WINED3DRS_FOGSTART ,
5935 WINED3DRS_FOGTABLEMODE ,
5936 WINED3DRS_FOGVERTEXMODE ,
5937 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5938 WINED3DRS_LIGHTING ,
5939 WINED3DRS_LOCALVIEWER ,
5940 WINED3DRS_MULTISAMPLEANTIALIAS ,
5941 WINED3DRS_MULTISAMPLEMASK ,
5942 WINED3DRS_NORMALIZENORMALS ,
5943 WINED3DRS_PATCHEDGESTYLE ,
5944 WINED3DRS_POINTSCALE_A ,
5945 WINED3DRS_POINTSCALE_B ,
5946 WINED3DRS_POINTSCALE_C ,
5947 WINED3DRS_POINTSCALEENABLE ,
5948 WINED3DRS_POINTSIZE ,
5949 WINED3DRS_POINTSIZE_MAX ,
5950 WINED3DRS_POINTSIZE_MIN ,
5951 WINED3DRS_POINTSPRITEENABLE ,
5952 WINED3DRS_RANGEFOGENABLE ,
5953 WINED3DRS_SPECULARMATERIALSOURCE ,
5954 WINED3DRS_TWEENFACTOR ,
5955 WINED3DRS_VERTEXBLEND
5958 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5959 WINED3DTSS_TEXCOORDINDEX ,
5960 WINED3DTSS_TEXTURETRANSFORMFLAGS
5963 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5964 WINED3DSAMP_DMAPOFFSET
5967 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5968 DWORD rep = StateTable[state].representative;
5972 WineD3DContext *context;
5975 for(i = 0; i < This->numContexts; i++) {
5976 context = This->contexts[i];
5977 if(isStateDirty(context, rep)) continue;
5979 context->dirtyArray[context->numDirtyEntries++] = rep;
5982 context->isStateDirty[idx] |= (1 << shift);