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-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->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 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
262 case WINED3DUSAGE_WRITEONLY:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
662 /* ************************************
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
671 ******************************** */
673 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
688 *******************************/
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
768 case WINED3DPOOL_SCRATCH:
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
809 /* Check if a 3D adapter is available when creating gl surfaces */
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
819 object->lpVtbl = &IWineGDISurface_Vtbl;
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
851 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
853 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
855 /* TODO: It should only be possible to create textures for formats
856 that are reported as supported */
857 if (WINED3DFMT_UNKNOWN >= Format) {
858 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
859 return WINED3DERR_INVALIDCALL;
862 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
863 D3DINITIALIZEBASETEXTURE(object->baseTexture);
864 object->width = Width;
865 object->height = Height;
867 /** Non-power2 support **/
868 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
872 /* Find the nearest pow2 match */
873 pow2Width = pow2Height = 1;
874 while (pow2Width < Width) pow2Width <<= 1;
875 while (pow2Height < Height) pow2Height <<= 1;
878 /** FIXME: add support for real non-power-two if it's provided by the video card **/
879 /* Precalculated scaling for 'faked' non power of two texture coords */
880 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
881 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
882 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
884 /* Calculate levels for mip mapping */
886 TRACE("calculating levels %d\n", object->baseTexture.levels);
887 object->baseTexture.levels++;
890 while (tmpW > 1 || tmpH > 1) {
891 tmpW = max(1, tmpW >> 1);
892 tmpH = max(1, tmpH >> 1);
893 object->baseTexture.levels++;
895 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
898 /* Generate all the surfaces */
901 for (i = 0; i < object->baseTexture.levels; i++)
903 /* use the callback to create the texture surface */
904 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
905 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
906 FIXME("Failed to create surface %p\n", object);
908 object->surfaces[i] = NULL;
909 IWineD3DTexture_Release((IWineD3DTexture *)object);
915 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
916 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
917 /* calculate the next mipmap level */
918 tmpW = max(1, tmpW >> 1);
919 tmpH = max(1, tmpH >> 1);
922 TRACE("(%p) : Created texture %p\n", This, object);
926 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
927 UINT Width, UINT Height, UINT Depth,
928 UINT Levels, DWORD Usage,
929 WINED3DFORMAT Format, WINED3DPOOL Pool,
930 IWineD3DVolumeTexture **ppVolumeTexture,
931 HANDLE *pSharedHandle, IUnknown *parent,
932 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
935 IWineD3DVolumeTextureImpl *object;
941 /* TODO: It should only be possible to create textures for formats
942 that are reported as supported */
943 if (WINED3DFMT_UNKNOWN >= Format) {
944 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
945 return WINED3DERR_INVALIDCALL;
948 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
949 D3DINITIALIZEBASETEXTURE(object->baseTexture);
951 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
952 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
954 object->width = Width;
955 object->height = Height;
956 object->depth = Depth;
958 /* Calculate levels for mip mapping */
960 object->baseTexture.levels++;
964 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
965 tmpW = max(1, tmpW >> 1);
966 tmpH = max(1, tmpH >> 1);
967 tmpD = max(1, tmpD >> 1);
968 object->baseTexture.levels++;
970 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
973 /* Generate all the surfaces */
978 for (i = 0; i < object->baseTexture.levels; i++)
981 /* Create the volume */
982 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
983 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
986 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
987 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
988 *ppVolumeTexture = NULL;
992 /* Set its container to this object */
993 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
995 /* calcualte the next mipmap level */
996 tmpW = max(1, tmpW >> 1);
997 tmpH = max(1, tmpH >> 1);
998 tmpD = max(1, tmpD >> 1);
1001 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1002 TRACE("(%p) : Created volume texture %p\n", This, object);
1006 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1007 UINT Width, UINT Height, UINT Depth,
1009 WINED3DFORMAT Format, WINED3DPOOL Pool,
1010 IWineD3DVolume** ppVolume,
1011 HANDLE* pSharedHandle, IUnknown *parent) {
1013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1014 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1015 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1017 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1019 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1020 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1022 object->currentDesc.Width = Width;
1023 object->currentDesc.Height = Height;
1024 object->currentDesc.Depth = Depth;
1025 object->bytesPerPixel = formatDesc->bpp;
1027 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1028 object->lockable = TRUE;
1029 object->locked = FALSE;
1030 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1031 object->dirty = TRUE;
1033 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1036 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1037 UINT Levels, DWORD Usage,
1038 WINED3DFORMAT Format, WINED3DPOOL Pool,
1039 IWineD3DCubeTexture **ppCubeTexture,
1040 HANDLE *pSharedHandle, IUnknown *parent,
1041 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1044 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1048 unsigned int pow2EdgeLength = EdgeLength;
1050 /* TODO: It should only be possible to create textures for formats
1051 that are reported as supported */
1052 if (WINED3DFMT_UNKNOWN >= Format) {
1053 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1054 return WINED3DERR_INVALIDCALL;
1057 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1058 WARN("(%p) : Tried to create not supported cube texture\n", This);
1059 return WINED3DERR_INVALIDCALL;
1062 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1063 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1065 TRACE("(%p) Create Cube Texture\n", This);
1067 /** Non-power2 support **/
1069 /* Find the nearest pow2 match */
1071 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1073 object->edgeLength = EdgeLength;
1074 /* TODO: support for native non-power 2 */
1075 /* Precalculated scaling for 'faked' non power of two texture coords */
1076 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1078 /* Calculate levels for mip mapping */
1080 object->baseTexture.levels++;
1083 tmpW = max(1, tmpW >> 1);
1084 object->baseTexture.levels++;
1086 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1089 /* Generate all the surfaces */
1091 for (i = 0; i < object->baseTexture.levels; i++) {
1093 /* Create the 6 faces */
1094 for (j = 0; j < 6; j++) {
1096 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1097 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1099 if(hr!= WINED3D_OK) {
1103 for (l = 0; l < j; l++) {
1104 IWineD3DSurface_Release(object->surfaces[j][i]);
1106 for (k = 0; k < i; k++) {
1107 for (l = 0; l < 6; l++) {
1108 IWineD3DSurface_Release(object->surfaces[l][j]);
1112 FIXME("(%p) Failed to create surface\n",object);
1113 HeapFree(GetProcessHeap(),0,object);
1114 *ppCubeTexture = NULL;
1117 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1118 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1120 tmpW = max(1, tmpW >> 1);
1123 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1124 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1128 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1130 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1131 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1133 /* Just a check to see if we support this type of query */
1135 case WINED3DQUERYTYPE_OCCLUSION:
1136 TRACE("(%p) occlusion query\n", This);
1137 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1140 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1143 case WINED3DQUERYTYPE_EVENT:
1144 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1145 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1146 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1148 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1153 case WINED3DQUERYTYPE_VCACHE:
1154 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1155 case WINED3DQUERYTYPE_VERTEXSTATS:
1156 case WINED3DQUERYTYPE_TIMESTAMP:
1157 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1158 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1159 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1160 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1161 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1162 case WINED3DQUERYTYPE_PIXELTIMINGS:
1163 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1164 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1166 FIXME("(%p) Unhandled query type %d\n", This, Type);
1168 if(NULL == ppQuery || hr != WINED3D_OK) {
1172 D3DCREATEOBJECTINSTANCE(object, Query)
1173 object->type = Type;
1174 /* allocated the 'extended' data based on the type of query requested */
1176 case WINED3DQUERYTYPE_OCCLUSION:
1177 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1178 TRACE("(%p) Allocating data for an occlusion query\n", This);
1179 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1180 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1181 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1184 case WINED3DQUERYTYPE_EVENT:
1185 if(GL_SUPPORT(APPLE_FENCE)) {
1186 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1187 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1188 checkGLcall("glGenFencesAPPLE");
1189 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1190 } else if(GL_SUPPORT(NV_FENCE)) {
1191 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1192 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1193 checkGLcall("glGenFencesNV");
1194 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1198 case WINED3DQUERYTYPE_VCACHE:
1199 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1200 case WINED3DQUERYTYPE_VERTEXSTATS:
1201 case WINED3DQUERYTYPE_TIMESTAMP:
1202 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1203 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1204 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1205 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1206 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1207 case WINED3DQUERYTYPE_PIXELTIMINGS:
1208 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1209 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1211 object->extendedData = 0;
1212 FIXME("(%p) Unhandled query type %d\n",This , Type);
1214 TRACE("(%p) : Created Query %p\n", This, object);
1218 /*****************************************************************************
1219 * IWineD3DDeviceImpl_SetupFullscreenWindow
1221 * Helper function that modifies a HWND's Style and ExStyle for proper
1225 * iface: Pointer to the IWineD3DDevice interface
1226 * window: Window to setup
1228 *****************************************************************************/
1229 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1232 LONG style, exStyle;
1233 /* Don't do anything if an original style is stored.
1234 * That shouldn't happen
1236 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1237 if (This->style || This->exStyle) {
1238 ERR("(%p): Want to change the window parameters of HWND %p, but "
1239 "another style is stored for restoration afterwards\n", This, window);
1242 /* Get the parameters and save them */
1243 style = GetWindowLongW(window, GWL_STYLE);
1244 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1245 This->style = style;
1246 This->exStyle = exStyle;
1248 /* Filter out window decorations */
1249 style &= ~WS_CAPTION;
1250 style &= ~WS_THICKFRAME;
1251 exStyle &= ~WS_EX_WINDOWEDGE;
1252 exStyle &= ~WS_EX_CLIENTEDGE;
1254 /* Make sure the window is managed, otherwise we won't get keyboard input */
1255 style |= WS_POPUP | WS_SYSMENU;
1257 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1258 This->style, This->exStyle, style, exStyle);
1260 SetWindowLongW(window, GWL_STYLE, style);
1261 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1263 /* Inform the window about the update. */
1264 SetWindowPos(window, HWND_TOP, 0, 0,
1265 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1266 ShowWindow(window, SW_NORMAL);
1269 /*****************************************************************************
1270 * IWineD3DDeviceImpl_RestoreWindow
1272 * Helper function that restores a windows' properties when taking it out
1273 * of fullscreen mode
1276 * iface: Pointer to the IWineD3DDevice interface
1277 * window: Window to setup
1279 *****************************************************************************/
1280 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1283 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1284 * switch, do nothing
1286 if (!This->style && !This->exStyle) return;
1288 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1289 This, window, This->style, This->exStyle);
1291 SetWindowLongW(window, GWL_STYLE, This->style);
1292 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1294 /* Delete the old values */
1298 /* Inform the window about the update */
1299 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1300 0, 0, 0, 0, /* Pos, Size, ignored */
1301 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1304 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1305 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1307 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1308 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1312 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1313 HRESULT hr = WINED3D_OK;
1314 IUnknown *bufferParent;
1316 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1318 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1319 * does a device hold a reference to a swap chain giving them a lifetime of the device
1320 * or does the swap chain notify the device of its destruction.
1321 *******************************/
1323 /* Check the params */
1324 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1325 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1326 return WINED3DERR_INVALIDCALL;
1327 } else if (pPresentationParameters->BackBufferCount > 1) {
1328 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");
1331 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1333 /*********************
1334 * Lookup the window Handle and the relating X window handle
1335 ********************/
1337 /* Setup hwnd we are using, plus which display this equates to */
1338 object->win_handle = pPresentationParameters->hDeviceWindow;
1339 if (!object->win_handle) {
1340 object->win_handle = This->createParms.hFocusWindow;
1343 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1344 hDc = GetDC(object->win_handle);
1345 TRACE("Using hDc %p\n", hDc);
1348 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1349 return WINED3DERR_NOTAVAILABLE;
1352 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1353 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1354 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1355 ReleaseDC(object->win_handle, hDc);
1357 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1358 * then the corresponding dimension of the client area of the hDeviceWindow
1359 * (or the focus window, if hDeviceWindow is NULL) is taken.
1360 **********************/
1362 if (pPresentationParameters->Windowed &&
1363 ((pPresentationParameters->BackBufferWidth == 0) ||
1364 (pPresentationParameters->BackBufferHeight == 0) ||
1365 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1368 GetClientRect(object->win_handle, &Rect);
1370 if (pPresentationParameters->BackBufferWidth == 0) {
1371 pPresentationParameters->BackBufferWidth = Rect.right;
1372 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1374 if (pPresentationParameters->BackBufferHeight == 0) {
1375 pPresentationParameters->BackBufferHeight = Rect.bottom;
1376 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1378 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1379 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1380 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1384 /* Put the correct figures in the presentation parameters */
1385 TRACE("Copying across presentation parameters\n");
1386 object->presentParms = *pPresentationParameters;
1388 TRACE("calling rendertarget CB\n");
1389 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1391 object->presentParms.BackBufferWidth,
1392 object->presentParms.BackBufferHeight,
1393 object->presentParms.BackBufferFormat,
1394 object->presentParms.MultiSampleType,
1395 object->presentParms.MultiSampleQuality,
1396 TRUE /* Lockable */,
1397 &object->frontBuffer,
1398 NULL /* pShared (always null)*/);
1399 if (object->frontBuffer != NULL) {
1400 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1402 ERR("Failed to create the front buffer\n");
1407 * Create an opengl context for the display visual
1408 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1409 * use different properties after that point in time. FIXME: How to handle when requested format
1410 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1411 * it chooses is identical to the one already being used!
1412 **********************************/
1413 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1415 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1416 if(!object->context)
1417 return E_OUTOFMEMORY;
1418 object->num_contexts = 1;
1421 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1424 if (!object->context[0]) {
1425 ERR("Failed to create a new context\n");
1426 hr = WINED3DERR_NOTAVAILABLE;
1429 TRACE("Context created (HWND=%p, glContext=%p)\n",
1430 object->win_handle, object->context[0]->glCtx);
1433 /*********************
1434 * Windowed / Fullscreen
1435 *******************/
1438 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1439 * so we should really check to see if there is a fullscreen swapchain already
1440 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1441 **************************************/
1443 if (!pPresentationParameters->Windowed) {
1450 /* Get info on the current display setup */
1452 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1455 /* Change the display settings */
1456 memset(&devmode, 0, sizeof(devmode));
1457 devmode.dmSize = sizeof(devmode);
1458 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1459 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1460 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1461 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1462 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1464 /* For GetDisplayMode */
1465 This->ddraw_width = devmode.dmPelsWidth;
1466 This->ddraw_height = devmode.dmPelsHeight;
1467 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1469 IWineD3DDevice_SetFullscreen(iface, TRUE);
1471 /* And finally clip mouse to our screen */
1472 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1473 ClipCursor(&clip_rc);
1476 /*********************
1477 * Create the back, front and stencil buffers
1478 *******************/
1479 if(object->presentParms.BackBufferCount > 0) {
1482 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1483 if(!object->backBuffer) {
1484 ERR("Out of memory\n");
1489 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1490 TRACE("calling rendertarget CB\n");
1491 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1493 object->presentParms.BackBufferWidth,
1494 object->presentParms.BackBufferHeight,
1495 object->presentParms.BackBufferFormat,
1496 object->presentParms.MultiSampleType,
1497 object->presentParms.MultiSampleQuality,
1498 TRUE /* Lockable */,
1499 &object->backBuffer[i],
1500 NULL /* pShared (always null)*/);
1501 if(hr == WINED3D_OK && object->backBuffer[i]) {
1502 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1504 ERR("Cannot create new back buffer\n");
1508 glDrawBuffer(GL_BACK);
1509 checkGLcall("glDrawBuffer(GL_BACK)");
1513 object->backBuffer = NULL;
1515 /* Single buffering - draw to front buffer */
1517 glDrawBuffer(GL_FRONT);
1518 checkGLcall("glDrawBuffer(GL_FRONT)");
1522 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1523 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1524 TRACE("Creating depth stencil buffer\n");
1525 if (This->depthStencilBuffer == NULL ) {
1526 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1528 object->presentParms.BackBufferWidth,
1529 object->presentParms.BackBufferHeight,
1530 object->presentParms.AutoDepthStencilFormat,
1531 object->presentParms.MultiSampleType,
1532 object->presentParms.MultiSampleQuality,
1533 FALSE /* FIXME: Discard */,
1534 &This->depthStencilBuffer,
1535 NULL /* pShared (always null)*/ );
1536 if (This->depthStencilBuffer != NULL)
1537 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1540 /** TODO: A check on width, height and multisample types
1541 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1542 ****************************/
1543 object->wantsDepthStencilBuffer = TRUE;
1545 object->wantsDepthStencilBuffer = FALSE;
1548 TRACE("Created swapchain %p\n", object);
1549 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1553 if (object->backBuffer) {
1555 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1556 if(object->backBuffer[i]) {
1557 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1558 IUnknown_Release(bufferParent); /* once for the get parent */
1559 if (IUnknown_Release(bufferParent) > 0) {
1560 FIXME("(%p) Something's still holding the back buffer\n",This);
1564 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1565 object->backBuffer = NULL;
1567 if(object->context[0])
1568 DestroyContext(This, object->context[0]);
1569 if(object->frontBuffer) {
1570 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1571 IUnknown_Release(bufferParent); /* once for the get parent */
1572 if (IUnknown_Release(bufferParent) > 0) {
1573 FIXME("(%p) Something's still holding the front buffer\n",This);
1576 HeapFree(GetProcessHeap(), 0, object);
1580 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1581 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 TRACE("(%p)\n", This);
1585 return This->NumberOfSwapChains;
1588 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1590 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1592 if(iSwapChain < This->NumberOfSwapChains) {
1593 *pSwapChain = This->swapchains[iSwapChain];
1594 IWineD3DSwapChain_AddRef(*pSwapChain);
1595 TRACE("(%p) returning %p\n", This, *pSwapChain);
1598 TRACE("Swapchain out of range\n");
1600 return WINED3DERR_INVALIDCALL;
1605 * Vertex Declaration
1607 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1608 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1610 IWineD3DVertexDeclarationImpl *object = NULL;
1611 HRESULT hr = WINED3D_OK;
1613 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1614 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1616 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1618 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1623 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1625 unsigned int idx, idx2;
1626 unsigned int offset;
1627 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1628 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1629 BOOL has_blend_idx = has_blend &&
1630 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1631 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1632 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1633 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1634 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1635 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1636 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1638 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1639 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1641 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1642 WINED3DVERTEXELEMENT *elements = NULL;
1645 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1646 if (has_blend_idx) num_blends--;
1648 /* Compute declaration size */
1649 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1650 has_psize + has_diffuse + has_specular + num_textures + 1;
1652 /* convert the declaration */
1653 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1657 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1660 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1661 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1662 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1665 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1666 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1668 elements[idx].UsageIndex = 0;
1671 if (has_blend && (num_blends > 0)) {
1672 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1673 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1675 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1676 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1677 elements[idx].UsageIndex = 0;
1680 if (has_blend_idx) {
1681 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1682 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1683 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1684 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1685 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1687 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1688 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1689 elements[idx].UsageIndex = 0;
1693 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1694 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1695 elements[idx].UsageIndex = 0;
1699 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1700 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1701 elements[idx].UsageIndex = 0;
1705 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1706 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1707 elements[idx].UsageIndex = 0;
1711 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1712 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1713 elements[idx].UsageIndex = 1;
1716 for (idx2 = 0; idx2 < num_textures; idx2++) {
1717 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1718 switch (numcoords) {
1719 case WINED3DFVF_TEXTUREFORMAT1:
1720 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1722 case WINED3DFVF_TEXTUREFORMAT2:
1723 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1725 case WINED3DFVF_TEXTUREFORMAT3:
1726 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1728 case WINED3DFVF_TEXTUREFORMAT4:
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1732 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1733 elements[idx].UsageIndex = idx2;
1737 /* Now compute offsets, and initialize the rest of the fields */
1738 for (idx = 0, offset = 0; idx < size-1; idx++) {
1739 elements[idx].Stream = 0;
1740 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1741 elements[idx].Offset = offset;
1742 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1745 *ppVertexElements = elements;
1749 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1750 WINED3DVERTEXELEMENT* elements = NULL;
1754 size = ConvertFvfToDeclaration(Fvf, &elements);
1755 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1757 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1758 HeapFree(GetProcessHeap(), 0, elements);
1759 if (hr != S_OK) return hr;
1764 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1765 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1767 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1768 HRESULT hr = WINED3D_OK;
1769 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1770 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1772 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1774 if (vertex_declaration) {
1775 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1778 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1780 if (WINED3D_OK != hr) {
1781 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1782 IWineD3DVertexShader_Release(*ppVertexShader);
1783 return WINED3DERR_INVALIDCALL;
1789 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1791 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1792 HRESULT hr = WINED3D_OK;
1794 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1795 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1796 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1797 if (WINED3D_OK == hr) {
1798 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1800 WARN("(%p) : Failed to create pixel shader\n", This);
1806 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1808 IWineD3DPaletteImpl *object;
1810 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1812 /* Create the new object */
1813 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1815 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1816 return E_OUTOFMEMORY;
1819 object->lpVtbl = &IWineD3DPalette_Vtbl;
1821 object->Flags = Flags;
1822 object->parent = Parent;
1823 object->wineD3DDevice = This;
1824 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1826 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1829 HeapFree( GetProcessHeap(), 0, object);
1830 return E_OUTOFMEMORY;
1833 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1835 IWineD3DPalette_Release((IWineD3DPalette *) object);
1839 *Palette = (IWineD3DPalette *) object;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1846 IWineD3DSwapChainImpl *swapchain;
1850 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1851 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1853 /* TODO: Test if OpenGL is compiled in and loaded */
1855 TRACE("(%p) : Creating stateblock\n", This);
1856 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1857 hr = IWineD3DDevice_CreateStateBlock(iface,
1859 (IWineD3DStateBlock **)&This->stateBlock,
1861 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1862 WARN("Failed to create stateblock\n");
1865 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1866 This->updateStateBlock = This->stateBlock;
1867 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1869 hr = allocate_shader_constants(This->updateStateBlock);
1870 if (WINED3D_OK != hr)
1873 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1874 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1875 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1877 /* Initialize the texture unit mapping to a 1:1 mapping */
1878 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1879 if (state < GL_LIMITS(fragment_samplers)) {
1880 This->texUnitMap[state] = state;
1881 This->rev_tex_unit_map[state] = state;
1883 This->texUnitMap[state] = -1;
1884 This->rev_tex_unit_map[state] = -1;
1888 /* Setup the implicit swapchain */
1889 TRACE("Creating implicit swapchain\n");
1890 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1891 if (FAILED(hr) || !swapchain) {
1892 WARN("Failed to create implicit swapchain\n");
1896 This->NumberOfSwapChains = 1;
1897 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1898 if(!This->swapchains) {
1899 ERR("Out of memory!\n");
1900 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1901 return E_OUTOFMEMORY;
1903 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1905 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1907 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1908 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1909 This->render_targets[0] = swapchain->backBuffer[0];
1910 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1913 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1914 This->render_targets[0] = swapchain->frontBuffer;
1915 This->lastActiveRenderTarget = swapchain->frontBuffer;
1917 IWineD3DSurface_AddRef(This->render_targets[0]);
1918 This->activeContext = swapchain->context[0];
1919 This->lastThread = GetCurrentThreadId();
1921 /* Depth Stencil support */
1922 This->stencilBufferTarget = This->depthStencilBuffer;
1923 if (NULL != This->stencilBufferTarget) {
1924 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1927 /* Set up some starting GL setup */
1930 /* Setup all the devices defaults */
1931 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1933 IWineD3DImpl_CheckGraphicsMemory();
1936 { /* Set a default viewport */
1940 vp.Width = pPresentationParameters->BackBufferWidth;
1941 vp.Height = pPresentationParameters->BackBufferHeight;
1944 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1947 /* Initialize the current view state */
1948 This->view_ident = 1;
1949 This->contexts[0]->last_was_rhw = 0;
1950 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1951 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1953 switch(wined3d_settings.offscreen_rendering_mode) {
1956 This->offscreenBuffer = GL_BACK;
1959 case ORM_BACKBUFFER:
1961 if(GL_LIMITS(aux_buffers) > 0) {
1962 TRACE("Using auxilliary buffer for offscreen rendering\n");
1963 This->offscreenBuffer = GL_AUX0;
1965 TRACE("Using back buffer for offscreen rendering\n");
1966 This->offscreenBuffer = GL_BACK;
1971 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1974 /* Clear the screen */
1975 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1976 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1979 This->d3d_initialized = TRUE;
1983 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 TRACE("(%p)\n", This);
1989 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1991 /* I don't think that the interface guarants that the device is destroyed from the same thread
1992 * it was created. Thus make sure a context is active for the glDelete* calls
1994 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1996 TRACE("Deleting high order patches\n");
1997 for(i = 0; i < PATCHMAP_SIZE; i++) {
1998 struct list *e1, *e2;
1999 struct WineD3DRectPatch *patch;
2000 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2001 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2002 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2006 /* Delete the pbuffer context if there is any */
2007 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2009 /* Delete the mouse cursor texture */
2010 if(This->cursorTexture) {
2012 glDeleteTextures(1, &This->cursorTexture);
2014 This->cursorTexture = 0;
2017 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2018 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2020 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2021 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2024 /* Release the update stateblock */
2025 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2026 if(This->updateStateBlock != This->stateBlock)
2027 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2029 This->updateStateBlock = NULL;
2031 { /* because were not doing proper internal refcounts releasing the primary state block
2032 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2033 to set this->stateBlock = NULL; first */
2034 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2035 This->stateBlock = NULL;
2037 /* Release the stateblock */
2038 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2039 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2043 /* Release the buffers (with sanity checks)*/
2044 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2045 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2046 if(This->depthStencilBuffer != This->stencilBufferTarget)
2047 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2049 This->stencilBufferTarget = NULL;
2051 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2052 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2053 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2055 TRACE("Setting rendertarget to NULL\n");
2056 This->render_targets[0] = NULL;
2058 if (This->depthStencilBuffer) {
2059 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2060 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2062 This->depthStencilBuffer = NULL;
2065 for(i=0; i < This->NumberOfSwapChains; i++) {
2066 TRACE("Releasing the implicit swapchain %d\n", i);
2067 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2068 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2072 HeapFree(GetProcessHeap(), 0, This->swapchains);
2073 This->swapchains = NULL;
2074 This->NumberOfSwapChains = 0;
2076 HeapFree(GetProcessHeap(), 0, This->render_targets);
2077 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2078 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2079 This->render_targets = NULL;
2080 This->fbo_color_attachments = NULL;
2081 This->draw_buffers = NULL;
2084 This->d3d_initialized = FALSE;
2088 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2090 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2092 /* Setup the window for fullscreen mode */
2093 if(fullscreen && !This->ddraw_fullscreen) {
2094 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2095 } else if(!fullscreen && This->ddraw_fullscreen) {
2096 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2099 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2100 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2101 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2104 This->ddraw_fullscreen = fullscreen;
2107 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2108 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2109 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2111 * There is no way to deactivate thread safety once it is enabled
2113 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2116 /*For now just store the flag(needed in case of ddraw) */
2117 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2122 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2126 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2129 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2131 /* Resize the screen even without a window:
2132 * The app could have unset it with SetCooperativeLevel, but not called
2133 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2134 * but we don't have any hwnd
2137 memset(&devmode, 0, sizeof(devmode));
2138 devmode.dmSize = sizeof(devmode);
2139 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2140 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2141 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2142 devmode.dmPelsWidth = pMode->Width;
2143 devmode.dmPelsHeight = pMode->Height;
2145 devmode.dmDisplayFrequency = pMode->RefreshRate;
2146 if (pMode->RefreshRate != 0) {
2147 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2150 /* Only change the mode if necessary */
2151 if( (This->ddraw_width == pMode->Width) &&
2152 (This->ddraw_height == pMode->Height) &&
2153 (This->ddraw_format == pMode->Format) &&
2154 (pMode->RefreshRate == 0) ) {
2158 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2159 if (ret != DISP_CHANGE_SUCCESSFUL) {
2160 if(devmode.dmDisplayFrequency != 0) {
2161 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2162 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2163 devmode.dmDisplayFrequency = 0;
2164 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2166 if(ret != DISP_CHANGE_SUCCESSFUL) {
2167 return WINED3DERR_NOTAVAILABLE;
2171 /* Store the new values */
2172 This->ddraw_width = pMode->Width;
2173 This->ddraw_height = pMode->Height;
2174 This->ddraw_format = pMode->Format;
2176 /* Only do this with a window of course */
2177 if(This->ddraw_window)
2178 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2180 /* And finally clip mouse to our screen */
2181 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2182 ClipCursor(&clip_rc);
2187 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2189 *ppD3D= This->wineD3D;
2190 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2191 IWineD3D_AddRef(*ppD3D);
2195 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2196 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2197 * into the video ram as possible and seeing how many fit
2198 * you can also get the correct initial value from nvidia and ATI's driver via X
2199 * texture memory is video memory + AGP memory
2200 *******************/
2201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2202 static BOOL showfixmes = TRUE;
2204 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2205 (wined3d_settings.emulated_textureram/(1024*1024)),
2206 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2209 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2210 (wined3d_settings.emulated_textureram/(1024*1024)),
2211 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2212 /* return simulated texture memory left */
2213 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2221 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2224 /* Update the current state block */
2225 This->updateStateBlock->changed.fvf = TRUE;
2227 if(This->updateStateBlock->fvf == fvf) {
2228 TRACE("Application is setting the old fvf over, nothing to do\n");
2232 This->updateStateBlock->fvf = fvf;
2233 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2239 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2241 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2242 *pfvf = This->stateBlock->fvf;
2247 * Get / Set Stream Source
2249 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 IWineD3DVertexBuffer *oldSrc;
2253 if (StreamNumber >= MAX_STREAMS) {
2254 WARN("Stream out of range %d\n", StreamNumber);
2255 return WINED3DERR_INVALIDCALL;
2258 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2259 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2261 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2263 if(oldSrc == pStreamData &&
2264 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2265 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2266 TRACE("Application is setting the old values over, nothing to do\n");
2270 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2272 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2273 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2276 /* Handle recording of state blocks */
2277 if (This->isRecordingState) {
2278 TRACE("Recording... not performing anything\n");
2279 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2280 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2284 /* Need to do a getParent and pass the reffs up */
2285 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2286 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2287 so for now, just count internally */
2288 if (pStreamData != NULL) {
2289 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2290 InterlockedIncrement(&vbImpl->bindCount);
2291 IWineD3DVertexBuffer_AddRef(pStreamData);
2293 if (oldSrc != NULL) {
2294 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2295 IWineD3DVertexBuffer_Release(oldSrc);
2298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2303 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2306 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2307 This->stateBlock->streamSource[StreamNumber],
2308 This->stateBlock->streamOffset[StreamNumber],
2309 This->stateBlock->streamStride[StreamNumber]);
2311 if (StreamNumber >= MAX_STREAMS) {
2312 WARN("Stream out of range %d\n", StreamNumber);
2313 return WINED3DERR_INVALIDCALL;
2315 *pStream = This->stateBlock->streamSource[StreamNumber];
2316 *pStride = This->stateBlock->streamStride[StreamNumber];
2318 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2321 if (*pStream != NULL) {
2322 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2327 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2330 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2332 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2333 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2335 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2336 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2338 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2339 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2340 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2346 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2349 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2350 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2352 TRACE("(%p) : returning %d\n", This, *Divider);
2358 * Get / Set & Multiply Transform
2360 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2363 /* Most of this routine, comments included copied from ddraw tree initially: */
2364 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2366 /* Handle recording of state blocks */
2367 if (This->isRecordingState) {
2368 TRACE("Recording... not performing anything\n");
2369 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2370 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2375 * If the new matrix is the same as the current one,
2376 * we cut off any further processing. this seems to be a reasonable
2377 * optimization because as was noticed, some apps (warcraft3 for example)
2378 * tend towards setting the same matrix repeatedly for some reason.
2380 * From here on we assume that the new matrix is different, wherever it matters.
2382 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2383 TRACE("The app is setting the same matrix over again\n");
2386 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2390 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2391 where ViewMat = Camera space, WorldMat = world space.
2393 In OpenGL, camera and world space is combined into GL_MODELVIEW
2394 matrix. The Projection matrix stay projection matrix.
2397 /* Capture the times we can just ignore the change for now */
2398 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2399 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2400 /* Handled by the state manager */
2403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2407 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2410 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2414 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2415 WINED3DMATRIX *mat = NULL;
2418 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2419 * below means it will be recorded in a state block change, but it
2420 * works regardless where it is recorded.
2421 * If this is found to be wrong, change to StateBlock.
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2424 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2426 if (State < HIGHEST_TRANSFORMSTATE)
2428 mat = &This->updateStateBlock->transforms[State];
2430 FIXME("Unhandled transform state!!\n");
2433 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2435 /* Apply change via set transform - will reapply to eg. lights this way */
2436 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2442 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2443 you can reference any indexes you want as long as that number max are enabled at any
2444 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2445 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2446 but when recording, just build a chain pretty much of commands to be replayed. */
2448 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2450 PLIGHTINFOEL *object = NULL;
2451 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2457 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2461 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2462 return WINED3DERR_INVALIDCALL;
2465 switch(pLight->Type) {
2466 case WINED3DLIGHT_POINT:
2467 case WINED3DLIGHT_SPOT:
2468 case WINED3DLIGHT_PARALLELPOINT:
2469 case WINED3DLIGHT_GLSPOT:
2470 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2473 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2474 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2475 return WINED3DERR_INVALIDCALL;
2479 case WINED3DLIGHT_DIRECTIONAL:
2480 /* Ignores attenuation */
2484 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2485 return WINED3DERR_INVALIDCALL;
2488 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2489 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2490 if(object->OriginalIndex == Index) break;
2495 TRACE("Adding new light\n");
2496 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2498 ERR("Out of memory error when allocating a light\n");
2499 return E_OUTOFMEMORY;
2501 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2502 object->glIndex = -1;
2503 object->OriginalIndex = Index;
2504 object->changed = TRUE;
2507 /* Initialize the object */
2508 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,
2509 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2510 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2511 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2512 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2513 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2514 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2516 /* Save away the information */
2517 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2519 switch (pLight->Type) {
2520 case WINED3DLIGHT_POINT:
2522 object->lightPosn[0] = pLight->Position.x;
2523 object->lightPosn[1] = pLight->Position.y;
2524 object->lightPosn[2] = pLight->Position.z;
2525 object->lightPosn[3] = 1.0f;
2526 object->cutoff = 180.0f;
2530 case WINED3DLIGHT_DIRECTIONAL:
2532 object->lightPosn[0] = -pLight->Direction.x;
2533 object->lightPosn[1] = -pLight->Direction.y;
2534 object->lightPosn[2] = -pLight->Direction.z;
2535 object->lightPosn[3] = 0.0;
2536 object->exponent = 0.0f;
2537 object->cutoff = 180.0f;
2540 case WINED3DLIGHT_SPOT:
2542 object->lightPosn[0] = pLight->Position.x;
2543 object->lightPosn[1] = pLight->Position.y;
2544 object->lightPosn[2] = pLight->Position.z;
2545 object->lightPosn[3] = 1.0;
2548 object->lightDirn[0] = pLight->Direction.x;
2549 object->lightDirn[1] = pLight->Direction.y;
2550 object->lightDirn[2] = pLight->Direction.z;
2551 object->lightDirn[3] = 1.0;
2554 * opengl-ish and d3d-ish spot lights use too different models for the
2555 * light "intensity" as a function of the angle towards the main light direction,
2556 * so we only can approximate very roughly.
2557 * however spot lights are rather rarely used in games (if ever used at all).
2558 * furthermore if still used, probably nobody pays attention to such details.
2560 if (pLight->Falloff == 0) {
2561 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2562 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2563 * will always be 1.0 for both of them, and we don't have to care for the
2564 * rest of the rather complex calculation
2566 object->exponent = 0;
2568 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2569 if (rho < 0.0001) rho = 0.0001f;
2570 object->exponent = -0.3/log(cos(rho/2));
2572 if (object->exponent > 128.0) {
2573 object->exponent = 128.0;
2575 object->cutoff = pLight->Phi*90/M_PI;
2581 FIXME("Unrecognized light type %d\n", pLight->Type);
2584 /* Update the live definitions if the light is currently assigned a glIndex */
2585 if (object->glIndex != -1 && !This->isRecordingState) {
2586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2591 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2592 PLIGHTINFOEL *lightInfo = NULL;
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2596 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2598 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2599 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2600 if(lightInfo->OriginalIndex == Index) break;
2604 if (lightInfo == NULL) {
2605 TRACE("Light information requested but light not defined\n");
2606 return WINED3DERR_INVALIDCALL;
2609 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2614 * Get / Set Light Enable
2615 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2617 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2618 PLIGHTINFOEL *lightInfo = NULL;
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2620 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2622 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2624 /* Tests show true = 128...not clear why */
2625 Enable = Enable? 128: 0;
2627 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2628 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2629 if(lightInfo->OriginalIndex == Index) break;
2632 TRACE("Found light: %p\n", lightInfo);
2634 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2635 if (lightInfo == NULL) {
2637 TRACE("Light enabled requested but light not defined, so defining one!\n");
2638 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2640 /* Search for it again! Should be fairly quick as near head of list */
2641 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2642 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2643 if(lightInfo->OriginalIndex == Index) break;
2646 if (lightInfo == NULL) {
2647 FIXME("Adding default lights has failed dismally\n");
2648 return WINED3DERR_INVALIDCALL;
2652 lightInfo->enabledChanged = TRUE;
2654 if(lightInfo->glIndex != -1) {
2655 if(!This->isRecordingState) {
2656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2659 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2660 lightInfo->glIndex = -1;
2662 TRACE("Light already disabled, nothing to do\n");
2665 if (lightInfo->glIndex != -1) {
2667 TRACE("Nothing to do as light was enabled\n");
2670 /* Find a free gl light */
2671 for(i = 0; i < This->maxConcurrentLights; i++) {
2672 if(This->stateBlock->activeLights[i] == NULL) {
2673 This->stateBlock->activeLights[i] = lightInfo;
2674 lightInfo->glIndex = i;
2678 if(lightInfo->glIndex == -1) {
2679 ERR("Too many concurrently active lights\n");
2680 return WINED3DERR_INVALIDCALL;
2683 /* i == lightInfo->glIndex */
2684 if(!This->isRecordingState) {
2685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2693 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2695 PLIGHTINFOEL *lightInfo = NULL;
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2699 TRACE("(%p) : for idx(%d)\n", This, Index);
2701 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2702 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2703 if(lightInfo->OriginalIndex == Index) break;
2707 if (lightInfo == NULL) {
2708 TRACE("Light enabled state requested but light not defined\n");
2709 return WINED3DERR_INVALIDCALL;
2711 /* true is 128 according to SetLightEnable */
2712 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2717 * Get / Set Clip Planes
2719 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2723 /* Validate Index */
2724 if (Index >= GL_LIMITS(clipplanes)) {
2725 TRACE("Application has requested clipplane this device doesn't support\n");
2726 return WINED3DERR_INVALIDCALL;
2729 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2731 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2732 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2733 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2734 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2735 TRACE("Application is setting old values over, nothing to do\n");
2739 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2740 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2741 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2742 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2744 /* Handle recording of state blocks */
2745 if (This->isRecordingState) {
2746 TRACE("Recording... not performing anything\n");
2750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2755 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2757 TRACE("(%p) : for idx %d\n", This, Index);
2759 /* Validate Index */
2760 if (Index >= GL_LIMITS(clipplanes)) {
2761 TRACE("Application has requested clipplane this device doesn't support\n");
2762 return WINED3DERR_INVALIDCALL;
2765 pPlane[0] = This->stateBlock->clipplane[Index][0];
2766 pPlane[1] = This->stateBlock->clipplane[Index][1];
2767 pPlane[2] = This->stateBlock->clipplane[Index][2];
2768 pPlane[3] = This->stateBlock->clipplane[Index][3];
2773 * Get / Set Clip Plane Status
2774 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2776 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2778 FIXME("(%p) : stub\n", This);
2779 if (NULL == pClipStatus) {
2780 return WINED3DERR_INVALIDCALL;
2782 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2783 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2787 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 FIXME("(%p) : stub\n", This);
2790 if (NULL == pClipStatus) {
2791 return WINED3DERR_INVALIDCALL;
2793 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2794 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2799 * Get / Set Material
2801 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 This->updateStateBlock->changed.material = TRUE;
2805 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2807 /* Handle recording of state blocks */
2808 if (This->isRecordingState) {
2809 TRACE("Recording... not performing anything\n");
2813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2817 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2819 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2820 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2821 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2822 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2823 pMaterial->Ambient.b, pMaterial->Ambient.a);
2824 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2825 pMaterial->Specular.b, pMaterial->Specular.a);
2826 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2827 pMaterial->Emissive.b, pMaterial->Emissive.a);
2828 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2836 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838 IWineD3DIndexBuffer *oldIdxs;
2840 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2841 oldIdxs = This->updateStateBlock->pIndexData;
2843 This->updateStateBlock->changed.indices = TRUE;
2844 This->updateStateBlock->pIndexData = pIndexData;
2846 /* Handle recording of state blocks */
2847 if (This->isRecordingState) {
2848 TRACE("Recording... not performing anything\n");
2849 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2850 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2854 if(oldIdxs != pIndexData) {
2855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2856 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2857 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2862 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2865 *ppIndexData = This->stateBlock->pIndexData;
2867 /* up ref count on ppindexdata */
2869 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2870 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2872 TRACE("(%p) No index data set\n", This);
2874 TRACE("Returning %p\n", *ppIndexData);
2879 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2880 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 TRACE("(%p)->(%d)\n", This, BaseIndex);
2884 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2885 TRACE("Application is setting the old value over, nothing to do\n");
2889 This->updateStateBlock->baseVertexIndex = BaseIndex;
2891 if (This->isRecordingState) {
2892 TRACE("Recording... not performing anything\n");
2895 /* The base vertex index affects the stream sources */
2896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2900 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 TRACE("(%p) : base_index %p\n", This, base_index);
2904 *base_index = This->stateBlock->baseVertexIndex;
2906 TRACE("Returning %u\n", *base_index);
2912 * Get / Set Viewports
2914 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2917 TRACE("(%p)\n", This);
2918 This->updateStateBlock->changed.viewport = TRUE;
2919 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2921 /* Handle recording of state blocks */
2922 if (This->isRecordingState) {
2923 TRACE("Recording... not performing anything\n");
2927 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2928 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2935 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 TRACE("(%p)\n", This);
2938 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2943 * Get / Set Render States
2944 * TODO: Verify against dx9 definitions
2946 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 DWORD oldValue = This->stateBlock->renderState[State];
2951 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2953 This->updateStateBlock->changed.renderState[State] = TRUE;
2954 This->updateStateBlock->renderState[State] = Value;
2956 /* Handle recording of state blocks */
2957 if (This->isRecordingState) {
2958 TRACE("Recording... not performing anything\n");
2962 /* Compared here and not before the assignment to allow proper stateblock recording */
2963 if(Value == oldValue) {
2964 TRACE("Application is setting the old value over, nothing to do\n");
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2972 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2975 *pValue = This->stateBlock->renderState[State];
2980 * Get / Set Sampler States
2981 * TODO: Verify against dx9 definitions
2984 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2989 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2991 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2992 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2996 * SetSampler is designed to allow for more than the standard up to 8 textures
2997 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2998 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3000 * http://developer.nvidia.com/object/General_FAQ.html#t6
3002 * There are two new settings for GForce
3004 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3005 * and the texture one:
3006 * GL_MAX_TEXTURE_COORDS_ARB.
3007 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3010 oldValue = This->stateBlock->samplerState[Sampler][Type];
3011 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3012 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3014 /* Handle recording of state blocks */
3015 if (This->isRecordingState) {
3016 TRACE("Recording... not performing anything\n");
3020 if(oldValue == Value) {
3021 TRACE("Application is setting the old value over, nothing to do\n");
3025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3030 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3034 This, Sampler, debug_d3dsamplerstate(Type), Type);
3036 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3037 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3040 *Value = This->stateBlock->samplerState[Sampler][Type];
3041 TRACE("(%p) : Returning %#x\n", This, *Value);
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 This->updateStateBlock->changed.scissorRect = TRUE;
3050 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3051 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3054 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3056 if(This->isRecordingState) {
3057 TRACE("Recording... not performing anything\n");
3061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3066 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3070 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3074 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3076 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3078 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3080 This->updateStateBlock->vertexDecl = pDecl;
3081 This->updateStateBlock->changed.vertexDecl = TRUE;
3083 if (This->isRecordingState) {
3084 TRACE("Recording... not performing anything\n");
3086 } else if(pDecl == oldDecl) {
3087 /* Checked after the assignment to allow proper stateblock recording */
3088 TRACE("Application is setting the old declaration over, nothing to do\n");
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3096 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3099 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3101 *ppDecl = This->stateBlock->vertexDecl;
3102 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3110 This->updateStateBlock->vertexShader = pShader;
3111 This->updateStateBlock->changed.vertexShader = TRUE;
3113 if (This->isRecordingState) {
3114 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3115 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3116 TRACE("Recording... not performing anything\n");
3118 } else if(oldShader == pShader) {
3119 /* Checked here to allow proper stateblock recording */
3120 TRACE("App is setting the old shader over, nothing to do\n");
3124 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3125 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3126 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3128 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 if (NULL == ppShader) {
3137 return WINED3DERR_INVALIDCALL;
3139 *ppShader = This->stateBlock->vertexShader;
3140 if( NULL != *ppShader)
3141 IWineD3DVertexShader_AddRef(*ppShader);
3143 TRACE("(%p) : returning %p\n", This, *ppShader);
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3148 IWineD3DDevice *iface,
3150 CONST BOOL *srcData,
3153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 int i, cnt = min(count, MAX_CONST_B - start);
3156 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3157 iface, srcData, start, count);
3159 if (srcData == NULL || cnt < 0)
3160 return WINED3DERR_INVALIDCALL;
3162 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3163 for (i = 0; i < cnt; i++)
3164 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3166 for (i = start; i < cnt + start; ++i) {
3167 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3176 IWineD3DDevice *iface,
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 int cnt = min(count, MAX_CONST_B - start);
3184 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3185 iface, dstData, start, count);
3187 if (dstData == NULL || cnt < 0)
3188 return WINED3DERR_INVALIDCALL;
3190 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3194 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3195 IWineD3DDevice *iface,
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 int i, cnt = min(count, MAX_CONST_I - start);
3203 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3204 iface, srcData, start, count);
3206 if (srcData == NULL || cnt < 0)
3207 return WINED3DERR_INVALIDCALL;
3209 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3210 for (i = 0; i < cnt; i++)
3211 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3212 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3214 for (i = start; i < cnt + start; ++i) {
3215 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3223 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3224 IWineD3DDevice *iface,
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 int cnt = min(count, MAX_CONST_I - start);
3232 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3233 iface, dstData, start, count);
3235 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3236 return WINED3DERR_INVALIDCALL;
3238 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3242 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3243 IWineD3DDevice *iface,
3245 CONST float *srcData,
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3252 iface, srcData, start, count);
3254 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3255 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3256 return WINED3DERR_INVALIDCALL;
3258 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3260 for (i = 0; i < count; i++)
3261 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3262 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3265 for (i = start; i < count + start; ++i) {
3266 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3267 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3268 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3269 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3270 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3272 ptr->idx[ptr->count++] = i;
3273 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3277 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3282 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3283 IWineD3DDevice *iface,
3288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3289 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3291 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3292 iface, dstData, start, count);
3294 if (dstData == NULL || cnt < 0)
3295 return WINED3DERR_INVALIDCALL;
3297 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3301 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3303 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3308 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3309 int i = This->rev_tex_unit_map[unit];
3310 int j = This->texUnitMap[stage];
3312 This->texUnitMap[stage] = unit;
3313 if (i != -1 && i != stage) {
3314 This->texUnitMap[i] = -1;
3317 This->rev_tex_unit_map[unit] = stage;
3318 if (j != -1 && j != unit) {
3319 This->rev_tex_unit_map[j] = -1;
3323 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3326 for (i = 0; i < MAX_TEXTURES; ++i) {
3327 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3328 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3329 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3330 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3331 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3332 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3333 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3334 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3336 if (color_op == WINED3DTOP_DISABLE) {
3337 /* Not used, and disable higher stages */
3338 while (i < MAX_TEXTURES) {
3339 This->fixed_function_usage_map[i] = FALSE;
3345 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3346 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3347 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3348 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3349 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3350 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3351 This->fixed_function_usage_map[i] = TRUE;
3353 This->fixed_function_usage_map[i] = FALSE;
3356 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3357 This->fixed_function_usage_map[i+1] = TRUE;
3362 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3365 device_update_fixed_function_usage_map(This);
3367 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3368 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3369 if (!This->fixed_function_usage_map[i]) continue;
3371 if (This->texUnitMap[i] != i) {
3372 device_map_stage(This, i, i);
3373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3374 markTextureStagesDirty(This, i);
3380 /* Now work out the mapping */
3382 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3383 if (!This->fixed_function_usage_map[i]) continue;
3385 if (This->texUnitMap[i] != tex) {
3386 device_map_stage(This, i, tex);
3387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3388 markTextureStagesDirty(This, i);
3395 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3396 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3399 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3400 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3401 device_map_stage(This, i, i);
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3403 if (i < MAX_TEXTURES) {
3404 markTextureStagesDirty(This, i);
3410 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3411 int current_mapping = This->rev_tex_unit_map[unit];
3413 if (current_mapping == -1) {
3414 /* Not currently used */
3418 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3419 /* Used by a fragment sampler */
3421 if (!pshader_sampler_tokens) {
3422 /* No pixel shader, check fixed function */
3423 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3426 /* Pixel shader, check the shader's sampler map */
3427 return !pshader_sampler_tokens[current_mapping];
3430 /* Used by a vertex sampler */
3431 return !vshader_sampler_tokens[current_mapping];
3434 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3435 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3436 DWORD *pshader_sampler_tokens = NULL;
3437 int start = GL_LIMITS(combined_samplers) - 1;
3441 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3443 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3444 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3445 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3448 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3449 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3450 if (vshader_sampler_tokens[i]) {
3451 if (This->texUnitMap[vsampler_idx] != -1) {
3452 /* Already mapped somewhere */
3456 while (start >= 0) {
3457 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3458 device_map_stage(This, vsampler_idx, start);
3459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3471 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3472 BOOL vs = use_vs(This);
3473 BOOL ps = use_ps(This);
3476 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3477 * that would be really messy and require shader recompilation
3478 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3479 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3482 device_map_psamplers(This);
3484 device_map_fixed_function_samplers(This);
3488 device_map_vsamplers(This, ps);
3492 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3494 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3495 This->updateStateBlock->pixelShader = pShader;
3496 This->updateStateBlock->changed.pixelShader = TRUE;
3498 /* Handle recording of state blocks */
3499 if (This->isRecordingState) {
3500 TRACE("Recording... not performing anything\n");
3503 if (This->isRecordingState) {
3504 TRACE("Recording... not performing anything\n");
3505 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3506 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3510 if(pShader == oldShader) {
3511 TRACE("App is setting the old pixel shader over, nothing to do\n");
3515 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3516 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3518 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3524 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3527 if (NULL == ppShader) {
3528 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3529 return WINED3DERR_INVALIDCALL;
3532 *ppShader = This->stateBlock->pixelShader;
3533 if (NULL != *ppShader) {
3534 IWineD3DPixelShader_AddRef(*ppShader);
3536 TRACE("(%p) : returning %p\n", This, *ppShader);
3540 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3541 IWineD3DDevice *iface,
3543 CONST BOOL *srcData,
3546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3547 int i, cnt = min(count, MAX_CONST_B - start);
3549 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3550 iface, srcData, start, count);
3552 if (srcData == NULL || cnt < 0)
3553 return WINED3DERR_INVALIDCALL;
3555 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3556 for (i = 0; i < cnt; i++)
3557 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3559 for (i = start; i < cnt + start; ++i) {
3560 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3568 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3569 IWineD3DDevice *iface,
3574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3575 int cnt = min(count, MAX_CONST_B - start);
3577 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3578 iface, dstData, start, count);
3580 if (dstData == NULL || cnt < 0)
3581 return WINED3DERR_INVALIDCALL;
3583 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3587 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3588 IWineD3DDevice *iface,
3593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3594 int i, cnt = min(count, MAX_CONST_I - start);
3596 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3597 iface, srcData, start, count);
3599 if (srcData == NULL || cnt < 0)
3600 return WINED3DERR_INVALIDCALL;
3602 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3603 for (i = 0; i < cnt; i++)
3604 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3605 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3607 for (i = start; i < cnt + start; ++i) {
3608 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3616 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3617 IWineD3DDevice *iface,
3622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3623 int cnt = min(count, MAX_CONST_I - start);
3625 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3626 iface, dstData, start, count);
3628 if (dstData == NULL || cnt < 0)
3629 return WINED3DERR_INVALIDCALL;
3631 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3635 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3636 IWineD3DDevice *iface,
3638 CONST float *srcData,
3641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3644 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3645 iface, srcData, start, count);
3647 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3648 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3649 return WINED3DERR_INVALIDCALL;
3651 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3653 for (i = 0; i < count; i++)
3654 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3655 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3658 for (i = start; i < count + start; ++i) {
3659 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3660 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3661 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3662 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3663 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3665 ptr->idx[ptr->count++] = i;
3666 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3670 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3675 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3676 IWineD3DDevice *iface,
3681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3682 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3684 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3685 iface, dstData, start, count);
3687 if (dstData == NULL || cnt < 0)
3688 return WINED3DERR_INVALIDCALL;
3690 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3694 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3696 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3697 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3699 DWORD DestFVF = dest->fvf;
3701 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3705 if (lpStrideData->u.s.normal.lpData) {
3706 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3709 if (lpStrideData->u.s.position.lpData == NULL) {
3710 ERR("Source has no position mask\n");
3711 return WINED3DERR_INVALIDCALL;
3714 /* We might access VBOs from this code, so hold the lock */
3717 if (dest->resource.allocatedMemory == NULL) {
3718 /* This may happen if we do direct locking into a vbo. Unlikely,
3719 * but theoretically possible(ddraw processvertices test)
3721 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3722 if(!dest->resource.allocatedMemory) {
3724 ERR("Out of memory\n");
3725 return E_OUTOFMEMORY;
3729 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3730 checkGLcall("glBindBufferARB");
3731 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3733 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3735 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3736 checkGLcall("glUnmapBufferARB");
3740 /* Get a pointer into the destination vbo(create one if none exists) and
3741 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3743 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3748 unsigned char extrabytes = 0;
3749 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3750 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3751 * this may write 4 extra bytes beyond the area that should be written
3753 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3754 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3755 if(!dest_conv_addr) {
3756 ERR("Out of memory\n");
3757 /* Continue without storing converted vertices */
3759 dest_conv = dest_conv_addr;
3763 * a) WINED3DRS_CLIPPING is enabled
3764 * b) WINED3DVOP_CLIP is passed
3766 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3767 static BOOL warned = FALSE;
3769 * The clipping code is not quite correct. Some things need
3770 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3771 * so disable clipping for now.
3772 * (The graphics in Half-Life are broken, and my processvertices
3773 * test crashes with IDirect3DDevice3)
3779 FIXME("Clipping is broken and disabled for now\n");
3781 } else doClip = FALSE;
3782 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3784 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3787 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3788 WINED3DTS_PROJECTION,
3790 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3791 WINED3DTS_WORLDMATRIX(0),
3794 TRACE("View mat:\n");
3795 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);
3796 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);
3797 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);
3798 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);
3800 TRACE("Proj mat:\n");
3801 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);
3802 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);
3803 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);
3804 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);
3806 TRACE("World mat:\n");
3807 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);
3808 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);
3809 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);
3810 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);
3812 /* Get the viewport */
3813 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3814 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3815 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3817 multiply_matrix(&mat,&view_mat,&world_mat);
3818 multiply_matrix(&mat,&proj_mat,&mat);
3820 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3822 for (i = 0; i < dwCount; i+= 1) {
3823 unsigned int tex_index;
3825 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3826 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3827 /* The position first */
3829 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3831 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3833 /* Multiplication with world, view and projection matrix */
3834 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);
3835 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);
3836 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);
3837 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);
3839 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3841 /* WARNING: The following things are taken from d3d7 and were not yet checked
3842 * against d3d8 or d3d9!
3845 /* Clipping conditions: From
3846 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3848 * A vertex is clipped if it does not match the following requirements
3852 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3854 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3855 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3860 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3861 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3864 /* "Normal" viewport transformation (not clipped)
3865 * 1) The values are divided by rhw
3866 * 2) The y axis is negative, so multiply it with -1
3867 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3868 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3869 * 4) Multiply x with Width/2 and add Width/2
3870 * 5) The same for the height
3871 * 6) Add the viewpoint X and Y to the 2D coordinates and
3872 * The minimum Z value to z
3873 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3875 * Well, basically it's simply a linear transformation into viewport
3887 z *= vp.MaxZ - vp.MinZ;
3889 x += vp.Width / 2 + vp.X;
3890 y += vp.Height / 2 + vp.Y;
3895 /* That vertex got clipped
3896 * Contrary to OpenGL it is not dropped completely, it just
3897 * undergoes a different calculation.
3899 TRACE("Vertex got clipped\n");
3906 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3907 * outside of the main vertex buffer memory. That needs some more
3912 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3915 ( (float *) dest_ptr)[0] = x;
3916 ( (float *) dest_ptr)[1] = y;
3917 ( (float *) dest_ptr)[2] = z;
3918 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3920 dest_ptr += 3 * sizeof(float);
3922 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3923 dest_ptr += sizeof(float);
3928 ( (float *) dest_conv)[0] = x * w;
3929 ( (float *) dest_conv)[1] = y * w;
3930 ( (float *) dest_conv)[2] = z * w;
3931 ( (float *) dest_conv)[3] = w;
3933 dest_conv += 3 * sizeof(float);
3935 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3936 dest_conv += sizeof(float);
3940 if (DestFVF & WINED3DFVF_PSIZE) {
3941 dest_ptr += sizeof(DWORD);
3942 if(dest_conv) dest_conv += sizeof(DWORD);
3944 if (DestFVF & WINED3DFVF_NORMAL) {
3946 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3947 /* AFAIK this should go into the lighting information */
3948 FIXME("Didn't expect the destination to have a normal\n");
3949 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3951 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3955 if (DestFVF & WINED3DFVF_DIFFUSE) {
3957 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3959 static BOOL warned = FALSE;
3962 ERR("No diffuse color in source, but destination has one\n");
3966 *( (DWORD *) dest_ptr) = 0xffffffff;
3967 dest_ptr += sizeof(DWORD);
3970 *( (DWORD *) dest_conv) = 0xffffffff;
3971 dest_conv += sizeof(DWORD);
3975 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3977 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3978 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3979 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3980 dest_conv += sizeof(DWORD);
3985 if (DestFVF & WINED3DFVF_SPECULAR) {
3986 /* What's the color value in the feedback buffer? */
3988 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3990 static BOOL warned = FALSE;
3993 ERR("No specular color in source, but destination has one\n");
3997 *( (DWORD *) dest_ptr) = 0xFF000000;
3998 dest_ptr += sizeof(DWORD);
4001 *( (DWORD *) dest_conv) = 0xFF000000;
4002 dest_conv += sizeof(DWORD);
4006 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4008 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4009 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4010 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4011 dest_conv += sizeof(DWORD);
4016 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4018 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4019 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4021 ERR("No source texture, but destination requests one\n");
4022 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4023 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4026 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4028 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4035 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4036 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4037 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4038 dwCount * get_flexible_vertex_size(DestFVF),
4040 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4041 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4048 #undef copy_and_next
4050 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 WineDirect3DVertexStridedData strided;
4053 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4054 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4057 ERR("Output vertex declaration not implemented yet\n");
4060 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4061 * and this call is quite performance critical, so don't call needlessly
4063 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4064 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4067 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4068 * control the streamIsUP flag, thus restore it afterwards.
4070 This->stateBlock->streamIsUP = FALSE;
4071 memset(&strided, 0, sizeof(strided));
4072 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4073 This->stateBlock->streamIsUP = streamWasUP;
4075 if(vbo || SrcStartIndex) {
4077 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4078 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4080 * Also get the start index in, but only loop over all elements if there's something to add at all.
4082 #define FIXSRC(type) \
4083 if(strided.u.s.type.VBO) { \
4084 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4085 strided.u.s.type.VBO = 0; \
4086 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4088 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4092 if(strided.u.s.type.lpData) { \
4093 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4096 FIXSRC(blendWeights);
4097 FIXSRC(blendMatrixIndices);
4102 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4103 FIXSRC(texCoords[i]);
4116 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4120 * Get / Set Texture Stage States
4121 * TODO: Verify against dx9 definitions
4123 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4125 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4127 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4129 if (Stage >= MAX_TEXTURES) {
4130 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4134 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4135 This->updateStateBlock->textureState[Stage][Type] = Value;
4137 if (This->isRecordingState) {
4138 TRACE("Recording... not performing anything\n");
4142 /* Checked after the assignments to allow proper stateblock recording */
4143 if(oldValue == Value) {
4144 TRACE("App is setting the old value over, nothing to do\n");
4148 if(Stage > This->stateBlock->lowest_disabled_stage &&
4149 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4150 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4151 * Changes in other states are important on disabled stages too
4156 if(Type == WINED3DTSS_COLOROP) {
4159 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4160 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4161 * they have to be disabled
4163 * The current stage is dirtified below.
4165 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4166 TRACE("Additionally dirtifying stage %d\n", i);
4167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4169 This->stateBlock->lowest_disabled_stage = Stage;
4170 TRACE("New lowest disabled: %d\n", Stage);
4171 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4172 /* Previously disabled stage enabled. Stages above it may need enabling
4173 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4174 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4176 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4179 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4180 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4183 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4186 This->stateBlock->lowest_disabled_stage = i;
4187 TRACE("New lowest disabled: %d\n", i);
4189 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4190 /* TODO: Built a stage -> texture unit mapping for register combiners */
4194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4199 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4201 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4202 *pValue = This->updateStateBlock->textureState[Stage][Type];
4209 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4211 IWineD3DBaseTexture *oldTexture;
4213 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4215 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4216 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4219 oldTexture = This->updateStateBlock->textures[Stage];
4221 if(pTexture != NULL) {
4222 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4224 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4225 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4226 return WINED3DERR_INVALIDCALL;
4228 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4231 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4232 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4234 This->updateStateBlock->changed.textures[Stage] = TRUE;
4235 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4236 This->updateStateBlock->textures[Stage] = pTexture;
4238 /* Handle recording of state blocks */
4239 if (This->isRecordingState) {
4240 TRACE("Recording... not performing anything\n");
4244 if(oldTexture == pTexture) {
4245 TRACE("App is setting the same texture again, nothing to do\n");
4249 /** NOTE: MSDN says that setTexture increases the reference count,
4250 * and the the application must set the texture back to null (or have a leaky application),
4251 * This means we should pass the refcount up to the parent
4252 *******************************/
4253 if (NULL != This->updateStateBlock->textures[Stage]) {
4254 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4255 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4257 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4258 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4259 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4260 * so the COLOROP and ALPHAOP have to be dirtified.
4262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4265 if(bindCount == 1) {
4266 new->baseTexture.sampler = Stage;
4268 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4272 if (NULL != oldTexture) {
4273 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4274 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4276 IWineD3DBaseTexture_Release(oldTexture);
4277 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4282 if(bindCount && old->baseTexture.sampler == Stage) {
4284 /* Have to do a search for the other sampler(s) where the texture is bound to
4285 * Shouldn't happen as long as apps bind a texture only to one stage
4287 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4288 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4289 if(This->updateStateBlock->textures[i] == oldTexture) {
4290 old->baseTexture.sampler = i;
4297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4302 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4307 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4308 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4311 *ppTexture=This->stateBlock->textures[Stage];
4313 IWineD3DBaseTexture_AddRef(*ppTexture);
4315 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4323 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4324 IWineD3DSurface **ppBackBuffer) {
4325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4326 IWineD3DSwapChain *swapChain;
4329 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4331 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4332 if (hr == WINED3D_OK) {
4333 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4334 IWineD3DSwapChain_Release(swapChain);
4336 *ppBackBuffer = NULL;
4341 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4343 WARN("(%p) : stub, calling idirect3d for now\n", This);
4344 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4347 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4349 IWineD3DSwapChain *swapChain;
4352 if(iSwapChain > 0) {
4353 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4354 if (hr == WINED3D_OK) {
4355 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4356 IWineD3DSwapChain_Release(swapChain);
4358 FIXME("(%p) Error getting display mode\n", This);
4361 /* Don't read the real display mode,
4362 but return the stored mode instead. X11 can't change the color
4363 depth, and some apps are pretty angry if they SetDisplayMode from
4364 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4366 Also don't relay to the swapchain because with ddraw it's possible
4367 that there isn't a swapchain at all */
4368 pMode->Width = This->ddraw_width;
4369 pMode->Height = This->ddraw_height;
4370 pMode->Format = This->ddraw_format;
4371 pMode->RefreshRate = 0;
4378 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4380 TRACE("(%p)->(%p)\n", This, hWnd);
4382 if(This->ddraw_fullscreen) {
4383 if(This->ddraw_window && This->ddraw_window != hWnd) {
4384 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4386 if(hWnd && This->ddraw_window != hWnd) {
4387 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4391 This->ddraw_window = hWnd;
4395 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4397 TRACE("(%p)->(%p)\n", This, hWnd);
4399 *hWnd = This->ddraw_window;
4404 * Stateblock related functions
4407 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4409 IWineD3DStateBlockImpl *object;
4410 HRESULT temp_result;
4413 TRACE("(%p)\n", This);
4415 if (This->isRecordingState) {
4416 return WINED3DERR_INVALIDCALL;
4419 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4420 if (NULL == object ) {
4421 FIXME("(%p)Error allocating memory for stateblock\n", This);
4422 return E_OUTOFMEMORY;
4424 TRACE("(%p) created object %p\n", This, object);
4425 object->wineD3DDevice= This;
4426 /** FIXME: object->parent = parent; **/
4427 object->parent = NULL;
4428 object->blockType = WINED3DSBT_RECORDED;
4430 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4432 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4433 list_init(&object->lightMap[i]);
4436 temp_result = allocate_shader_constants(object);
4437 if (WINED3D_OK != temp_result)
4440 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4441 This->updateStateBlock = object;
4442 This->isRecordingState = TRUE;
4444 TRACE("(%p) recording stateblock %p\n",This , object);
4448 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4451 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4453 if (!This->isRecordingState) {
4454 FIXME("(%p) not recording! returning error\n", This);
4455 *ppStateBlock = NULL;
4456 return WINED3DERR_INVALIDCALL;
4459 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4460 if(object->changed.renderState[i]) {
4461 object->contained_render_states[object->num_contained_render_states] = i;
4462 object->num_contained_render_states++;
4465 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4466 if(object->changed.transform[i]) {
4467 object->contained_transform_states[object->num_contained_transform_states] = i;
4468 object->num_contained_transform_states++;
4471 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4472 if(object->changed.vertexShaderConstantsF[i]) {
4473 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4474 object->num_contained_vs_consts_f++;
4477 for(i = 0; i < MAX_CONST_I; i++) {
4478 if(object->changed.vertexShaderConstantsI[i]) {
4479 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4480 object->num_contained_vs_consts_i++;
4483 for(i = 0; i < MAX_CONST_B; i++) {
4484 if(object->changed.vertexShaderConstantsB[i]) {
4485 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4486 object->num_contained_vs_consts_b++;
4489 for(i = 0; i < MAX_CONST_I; i++) {
4490 if(object->changed.pixelShaderConstantsI[i]) {
4491 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4492 object->num_contained_ps_consts_i++;
4495 for(i = 0; i < MAX_CONST_B; i++) {
4496 if(object->changed.pixelShaderConstantsB[i]) {
4497 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4498 object->num_contained_ps_consts_b++;
4501 for(i = 0; i < MAX_TEXTURES; i++) {
4502 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4503 if(object->changed.textureState[i][j]) {
4504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4505 object->contained_tss_states[object->num_contained_tss_states].state = j;
4506 object->num_contained_tss_states++;
4510 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4511 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4512 if(object->changed.samplerState[i][j]) {
4513 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4514 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4515 object->num_contained_sampler_states++;
4520 *ppStateBlock = (IWineD3DStateBlock*) object;
4521 This->isRecordingState = FALSE;
4522 This->updateStateBlock = This->stateBlock;
4523 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4524 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4525 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4530 * Scene related functions
4532 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4533 /* At the moment we have no need for any functionality at the beginning
4535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4536 TRACE("(%p)\n", This);
4539 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4540 return WINED3DERR_INVALIDCALL;
4542 This->inScene = TRUE;
4546 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4548 TRACE("(%p)\n", This);
4550 if(!This->inScene) {
4551 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4552 return WINED3DERR_INVALIDCALL;
4555 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4556 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4558 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4561 checkGLcall("glFlush");
4564 This->inScene = FALSE;
4568 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4569 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4570 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 IWineD3DSwapChain *swapChain = NULL;
4574 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4576 TRACE("(%p) Presenting the frame\n", This);
4578 for(i = 0 ; i < swapchains ; i ++) {
4580 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4581 TRACE("presentinng chain %d, %p\n", i, swapChain);
4582 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4583 IWineD3DSwapChain_Release(swapChain);
4589 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4590 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4592 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4594 GLbitfield glMask = 0;
4596 CONST WINED3DRECT* curRect;
4598 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4599 Count, pRects, Flags, Color, Z, Stencil);
4601 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4602 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4603 /* TODO: What about depth stencil buffers without stencil bits? */
4604 return WINED3DERR_INVALIDCALL;
4607 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4608 * and not the last active one.
4610 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4613 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4614 apply_fbo_state(iface);
4617 if (Count > 0 && pRects) {
4623 /* Only set the values up once, as they are not changing */
4624 if (Flags & WINED3DCLEAR_STENCIL) {
4625 glClearStencil(Stencil);
4626 checkGLcall("glClearStencil");
4627 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4628 glStencilMask(0xFFFFFFFF);
4631 if (Flags & WINED3DCLEAR_ZBUFFER) {
4632 glDepthMask(GL_TRUE);
4634 checkGLcall("glClearDepth");
4635 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4639 if (Flags & WINED3DCLEAR_TARGET) {
4640 TRACE("Clearing screen with glClear to color %x\n", Color);
4641 glClearColor(D3DCOLOR_R(Color),
4645 checkGLcall("glClearColor");
4647 /* Clear ALL colors! */
4648 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4649 glMask = glMask | GL_COLOR_BUFFER_BIT;
4653 /* In drawable flag is set below */
4655 if (This->render_offscreen) {
4656 glScissor(This->stateBlock->viewport.X,
4657 This->stateBlock->viewport.Y,
4658 This->stateBlock->viewport.Width,
4659 This->stateBlock->viewport.Height);
4661 glScissor(This->stateBlock->viewport.X,
4662 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4663 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4664 This->stateBlock->viewport.Width,
4665 This->stateBlock->viewport.Height);
4667 checkGLcall("glScissor");
4669 checkGLcall("glClear");
4671 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4672 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4674 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4675 curRect[0].x2 < target->currentDesc.Width ||
4676 curRect[0].y2 < target->currentDesc.Height) {
4677 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4678 blt_to_drawable(This, target);
4682 /* Now process each rect in turn */
4683 for (i = 0; i < Count; i++) {
4684 /* Note gl uses lower left, width/height */
4685 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4686 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4687 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4688 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4690 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4691 * The rectangle is not cleared, no error is returned, but further rectanlges are
4692 * still cleared if they are valid
4694 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4695 TRACE("Rectangle with negative dimensions, ignoring\n");
4699 if(This->render_offscreen) {
4700 glScissor(curRect[i].x1, curRect[i].y1,
4701 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4703 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4704 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4706 checkGLcall("glScissor");
4709 checkGLcall("glClear");
4713 /* Restore the old values (why..?) */
4714 if (Flags & WINED3DCLEAR_STENCIL) {
4715 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4717 if (Flags & WINED3DCLEAR_TARGET) {
4718 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4719 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4720 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4721 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4722 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4727 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4728 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4730 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4731 target->Flags |= SFLAG_INTEXTURE;
4732 target->Flags &= ~SFLAG_INSYSMEM;
4734 target->Flags |= SFLAG_INDRAWABLE;
4735 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4743 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4744 UINT PrimitiveCount) {
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4748 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4749 debug_d3dprimitivetype(PrimitiveType),
4750 StartVertex, PrimitiveCount);
4752 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4753 if(This->stateBlock->streamIsUP) {
4754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4755 This->stateBlock->streamIsUP = FALSE;
4758 if(This->stateBlock->loadBaseVertexIndex != 0) {
4759 This->stateBlock->loadBaseVertexIndex = 0;
4760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4762 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4763 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4764 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4768 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4769 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4770 WINED3DPRIMITIVETYPE PrimitiveType,
4771 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4775 IWineD3DIndexBuffer *pIB;
4776 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4779 pIB = This->stateBlock->pIndexData;
4781 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4782 * without an index buffer set. (The first time at least...)
4783 * D3D8 simply dies, but I doubt it can do much harm to return
4784 * D3DERR_INVALIDCALL there as well. */
4785 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4786 return WINED3DERR_INVALIDCALL;
4789 if(This->stateBlock->streamIsUP) {
4790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4791 This->stateBlock->streamIsUP = FALSE;
4793 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4795 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4796 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4797 minIndex, NumVertices, startIndex, primCount);
4799 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4800 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4806 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4807 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4811 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4812 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4817 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4818 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4819 UINT VertexStreamZeroStride) {
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4821 IWineD3DVertexBuffer *vb;
4823 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4824 debug_d3dprimitivetype(PrimitiveType),
4825 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4827 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4828 vb = This->stateBlock->streamSource[0];
4829 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4830 if(vb) IWineD3DVertexBuffer_Release(vb);
4831 This->stateBlock->streamOffset[0] = 0;
4832 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4833 This->stateBlock->streamIsUP = TRUE;
4834 This->stateBlock->loadBaseVertexIndex = 0;
4836 /* TODO: Only mark dirty if drawing from a different UP address */
4837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4839 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4840 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4842 /* MSDN specifies stream zero settings must be set to NULL */
4843 This->stateBlock->streamStride[0] = 0;
4844 This->stateBlock->streamSource[0] = NULL;
4846 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4847 * the new stream sources or use UP drawing again
4852 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4853 UINT MinVertexIndex, UINT NumVertices,
4854 UINT PrimitiveCount, CONST void* pIndexData,
4855 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4856 UINT VertexStreamZeroStride) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 IWineD3DVertexBuffer *vb;
4860 IWineD3DIndexBuffer *ib;
4862 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4863 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4864 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4865 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4867 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4873 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4874 vb = This->stateBlock->streamSource[0];
4875 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4876 if(vb) IWineD3DVertexBuffer_Release(vb);
4877 This->stateBlock->streamIsUP = TRUE;
4878 This->stateBlock->streamOffset[0] = 0;
4879 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4881 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4882 This->stateBlock->baseVertexIndex = 0;
4883 This->stateBlock->loadBaseVertexIndex = 0;
4884 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4888 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4890 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4891 This->stateBlock->streamSource[0] = NULL;
4892 This->stateBlock->streamStride[0] = 0;
4893 ib = This->stateBlock->pIndexData;
4895 IWineD3DIndexBuffer_Release(ib);
4896 This->stateBlock->pIndexData = NULL;
4898 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4899 * SetStreamSource to specify a vertex buffer
4905 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4908 /* Mark the state dirty until we have nicer tracking
4909 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4914 This->stateBlock->baseVertexIndex = 0;
4915 This->up_strided = DrawPrimStrideData;
4916 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4917 This->up_strided = NULL;
4921 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4923 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4925 /* Mark the state dirty until we have nicer tracking
4926 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4931 This->stateBlock->streamIsUP = TRUE;
4932 This->stateBlock->baseVertexIndex = 0;
4933 This->up_strided = DrawPrimStrideData;
4934 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4935 This->up_strided = NULL;
4940 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4941 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4943 HRESULT hr = WINED3D_OK;
4944 WINED3DRESOURCETYPE sourceType;
4945 WINED3DRESOURCETYPE destinationType;
4948 /* TODO: think about moving the code into IWineD3DBaseTexture */
4950 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4952 /* verify that the source and destination textures aren't NULL */
4953 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4954 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4955 This, pSourceTexture, pDestinationTexture);
4956 hr = WINED3DERR_INVALIDCALL;
4959 if (pSourceTexture == pDestinationTexture) {
4960 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4961 This, pSourceTexture, pDestinationTexture);
4962 hr = WINED3DERR_INVALIDCALL;
4964 /* Verify that the source and destination textures are the same type */
4965 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4966 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4968 if (sourceType != destinationType) {
4969 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4971 hr = WINED3DERR_INVALIDCALL;
4974 /* check that both textures have the identical numbers of levels */
4975 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4976 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4977 hr = WINED3DERR_INVALIDCALL;
4980 if (WINED3D_OK == hr) {
4982 /* Make sure that the destination texture is loaded */
4983 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4985 /* Update every surface level of the texture */
4986 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4988 switch (sourceType) {
4989 case WINED3DRTYPE_TEXTURE:
4991 IWineD3DSurface *srcSurface;
4992 IWineD3DSurface *destSurface;
4994 for (i = 0 ; i < levels ; ++i) {
4995 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4996 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4997 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4998 IWineD3DSurface_Release(srcSurface);
4999 IWineD3DSurface_Release(destSurface);
5000 if (WINED3D_OK != hr) {
5001 WARN("(%p) : Call to update surface failed\n", This);
5007 case WINED3DRTYPE_CUBETEXTURE:
5009 IWineD3DSurface *srcSurface;
5010 IWineD3DSurface *destSurface;
5011 WINED3DCUBEMAP_FACES faceType;
5013 for (i = 0 ; i < levels ; ++i) {
5014 /* Update each cube face */
5015 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5016 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5017 if (WINED3D_OK != hr) {
5018 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5020 TRACE("Got srcSurface %p\n", srcSurface);
5022 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5023 if (WINED3D_OK != hr) {
5024 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5026 TRACE("Got desrSurface %p\n", destSurface);
5028 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5029 IWineD3DSurface_Release(srcSurface);
5030 IWineD3DSurface_Release(destSurface);
5031 if (WINED3D_OK != hr) {
5032 WARN("(%p) : Call to update surface failed\n", This);
5039 #if 0 /* TODO: Add support for volume textures */
5040 case WINED3DRTYPE_VOLUMETEXTURE:
5042 IWineD3DVolume srcVolume = NULL;
5043 IWineD3DSurface destVolume = NULL;
5045 for (i = 0 ; i < levels ; ++i) {
5046 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5047 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5048 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5049 IWineD3DVolume_Release(srcSurface);
5050 IWineD3DVolume_Release(destSurface);
5051 if (WINED3D_OK != hr) {
5052 WARN("(%p) : Call to update volume failed\n", This);
5060 FIXME("(%p) : Unsupported source and destination type\n", This);
5061 hr = WINED3DERR_INVALIDCALL;
5068 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5069 IWineD3DSwapChain *swapChain;
5071 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5072 if(hr == WINED3D_OK) {
5073 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5074 IWineD3DSwapChain_Release(swapChain);
5079 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5081 /* return a sensible default */
5083 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5084 FIXME("(%p) : stub\n", This);
5088 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5092 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5093 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5094 return WINED3DERR_INVALIDCALL;
5096 for (j = 0; j < 256; ++j) {
5097 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5098 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5099 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5100 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5102 TRACE("(%p) : returning\n", This);
5106 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5109 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5110 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5111 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5112 return WINED3DERR_INVALIDCALL;
5114 for (j = 0; j < 256; ++j) {
5115 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5116 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5117 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5118 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5120 TRACE("(%p) : returning\n", This);
5124 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5127 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5128 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5129 return WINED3DERR_INVALIDCALL;
5131 /*TODO: stateblocks */
5132 This->currentPalette = PaletteNumber;
5133 TRACE("(%p) : returning\n", This);
5137 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5139 if (PaletteNumber == NULL) {
5140 WARN("(%p) : returning Invalid Call\n", This);
5141 return WINED3DERR_INVALIDCALL;
5143 /*TODO: stateblocks */
5144 *PaletteNumber = This->currentPalette;
5145 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5149 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 static BOOL showFixmes = TRUE;
5153 FIXME("(%p) : stub\n", This);
5157 This->softwareVertexProcessing = bSoftware;
5162 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 static BOOL showFixmes = TRUE;
5166 FIXME("(%p) : stub\n", This);
5169 return This->softwareVertexProcessing;
5173 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5175 IWineD3DSwapChain *swapChain;
5178 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5180 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5181 if(hr == WINED3D_OK){
5182 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5183 IWineD3DSwapChain_Release(swapChain);
5185 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5191 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5193 static BOOL showfixmes = TRUE;
5194 if(nSegments != 0.0f) {
5196 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5203 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205 static BOOL showfixmes = TRUE;
5207 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5213 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5215 /** TODO: remove casts to IWineD3DSurfaceImpl
5216 * NOTE: move code to surface to accomplish this
5217 ****************************************/
5218 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5219 int srcWidth, srcHeight;
5220 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5221 WINED3DFORMAT destFormat, srcFormat;
5223 int srcLeft, destLeft, destTop;
5224 WINED3DPOOL srcPool, destPool;
5226 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5227 glDescriptor *glDescription = NULL;
5230 CONVERT_TYPES convert = NO_CONVERSION;
5232 WINED3DSURFACE_DESC winedesc;
5234 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5235 memset(&winedesc, 0, sizeof(winedesc));
5236 winedesc.Width = &srcSurfaceWidth;
5237 winedesc.Height = &srcSurfaceHeight;
5238 winedesc.Pool = &srcPool;
5239 winedesc.Format = &srcFormat;
5241 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5243 winedesc.Width = &destSurfaceWidth;
5244 winedesc.Height = &destSurfaceHeight;
5245 winedesc.Pool = &destPool;
5246 winedesc.Format = &destFormat;
5247 winedesc.Size = &destSize;
5249 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5251 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5252 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5253 return WINED3DERR_INVALIDCALL;
5256 /* This call loads the opengl surface directly, instead of copying the surface to the
5257 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5258 * copy in sysmem and use regular surface loading.
5260 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5261 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5262 if(convert != NO_CONVERSION) {
5263 return IWineD3DSurface_BltFast(pDestinationSurface,
5264 pDestPoint ? pDestPoint->x : 0,
5265 pDestPoint ? pDestPoint->y : 0,
5266 pSourceSurface, (RECT *) pSourceRect, 0);
5269 if (destFormat == WINED3DFMT_UNKNOWN) {
5270 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5271 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5273 /* Get the update surface description */
5274 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5281 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5282 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5283 checkGLcall("glActiveTextureARB");
5286 /* Make sure the surface is loaded and up to date */
5287 IWineD3DSurface_PreLoad(pDestinationSurface);
5289 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5291 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5292 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5293 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5294 srcLeft = pSourceRect ? pSourceRect->left : 0;
5295 destLeft = pDestPoint ? pDestPoint->x : 0;
5296 destTop = pDestPoint ? pDestPoint->y : 0;
5299 /* This function doesn't support compressed textures
5300 the pitch is just bytesPerPixel * width */
5301 if(srcWidth != srcSurfaceWidth || srcLeft ){
5302 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5303 offset += srcLeft * pSrcSurface->bytesPerPixel;
5304 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5306 /* TODO DXT formats */
5308 if(pSourceRect != NULL && pSourceRect->top != 0){
5309 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5311 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5313 ,glDescription->level
5318 ,glDescription->glFormat
5319 ,glDescription->glType
5320 ,IWineD3DSurface_GetData(pSourceSurface)
5324 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5326 /* need to lock the surface to get the data */
5327 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5330 /* TODO: Cube and volume support */
5332 /* not a whole row so we have to do it a line at a time */
5335 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5336 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5338 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5340 glTexSubImage2D(glDescription->target
5341 ,glDescription->level
5346 ,glDescription->glFormat
5347 ,glDescription->glType
5348 ,data /* could be quicker using */
5353 } else { /* Full width, so just write out the whole texture */
5355 if (WINED3DFMT_DXT1 == destFormat ||
5356 WINED3DFMT_DXT2 == destFormat ||
5357 WINED3DFMT_DXT3 == destFormat ||
5358 WINED3DFMT_DXT4 == destFormat ||
5359 WINED3DFMT_DXT5 == destFormat) {
5360 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5361 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5362 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5363 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5364 } if (destFormat != srcFormat) {
5365 FIXME("Updating mixed format compressed texture is not curretly support\n");
5367 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5368 glDescription->level,
5369 glDescription->glFormatInternal,
5374 IWineD3DSurface_GetData(pSourceSurface));
5377 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5382 glTexSubImage2D(glDescription->target
5383 ,glDescription->level
5388 ,glDescription->glFormat
5389 ,glDescription->glType
5390 ,IWineD3DSurface_GetData(pSourceSurface)
5394 checkGLcall("glTexSubImage2D");
5398 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5399 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5405 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5407 struct WineD3DRectPatch *patch;
5411 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5413 if(!(Handle || pRectPatchInfo)) {
5414 /* TODO: Write a test for the return value, thus the FIXME */
5415 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5416 return WINED3DERR_INVALIDCALL;
5420 i = PATCHMAP_HASHFUNC(Handle);
5422 LIST_FOR_EACH(e, &This->patches[i]) {
5423 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5424 if(patch->Handle == Handle) {
5431 TRACE("Patch does not exist. Creating a new one\n");
5432 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5433 patch->Handle = Handle;
5434 list_add_head(&This->patches[i], &patch->entry);
5436 TRACE("Found existing patch %p\n", patch);
5439 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5440 * attributes we have to tesselate, read back, and draw. This needs a patch
5441 * management structure instance. Create one.
5443 * A possible improvement is to check if a vertex shader is used, and if not directly
5446 FIXME("Drawing an uncached patch. This is slow\n");
5447 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5450 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5451 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5452 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5454 TRACE("Tesselation density or patch info changed, retesselating\n");
5456 if(pRectPatchInfo) {
5457 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5459 patch->numSegs[0] = pNumSegs[0];
5460 patch->numSegs[1] = pNumSegs[1];
5461 patch->numSegs[2] = pNumSegs[2];
5462 patch->numSegs[3] = pNumSegs[3];
5464 hr = tesselate_rectpatch(This, patch);
5466 WARN("Patch tesselation failed\n");
5468 /* Do not release the handle to store the params of the patch */
5470 HeapFree(GetProcessHeap(), 0, patch);
5476 This->currentPatch = patch;
5477 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5478 This->currentPatch = NULL;
5480 /* Destroy uncached patches */
5482 HeapFree(GetProcessHeap(), 0, patch->mem);
5483 HeapFree(GetProcessHeap(), 0, patch);
5488 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5489 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5491 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5492 FIXME("(%p) : Stub\n", This);
5496 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5499 struct WineD3DRectPatch *patch;
5501 TRACE("(%p) Handle(%d)\n", This, Handle);
5503 i = PATCHMAP_HASHFUNC(Handle);
5504 LIST_FOR_EACH(e, &This->patches[i]) {
5505 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5506 if(patch->Handle == Handle) {
5507 TRACE("Deleting patch %p\n", patch);
5508 list_remove(&patch->entry);
5509 HeapFree(GetProcessHeap(), 0, patch->mem);
5510 HeapFree(GetProcessHeap(), 0, patch);
5515 /* TODO: Write a test for the return value */
5516 FIXME("Attempt to destroy nonexistant patch\n");
5517 return WINED3DERR_INVALIDCALL;
5520 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5522 IWineD3DSwapChain *swapchain;
5524 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5525 if (SUCCEEDED(hr)) {
5526 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5533 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5537 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5538 checkGLcall("glGenFramebuffersEXT()");
5540 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5541 checkGLcall("glBindFramebuffer()");
5544 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5545 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5546 IWineD3DBaseTextureImpl *texture_impl;
5547 GLenum texttarget, target;
5550 texttarget = surface_impl->glDescription.target;
5551 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5552 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5554 IWineD3DSurface_PreLoad(surface);
5556 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5557 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5558 glBindTexture(target, old_binding);
5560 /* Update base texture states array */
5561 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5562 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5563 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5564 if (texture_impl->baseTexture.bindCount) {
5565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5568 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5571 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5572 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5574 checkGLcall("attach_surface_fbo");
5577 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5579 IWineD3DSwapChain *swapchain;
5581 swapchain = get_swapchain(surface);
5585 TRACE("Surface %p is onscreen\n", surface);
5587 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5588 buffer = surface_get_gl_buffer(surface, swapchain);
5589 glDrawBuffer(buffer);
5590 checkGLcall("glDrawBuffer()");
5592 TRACE("Surface %p is offscreen\n", surface);
5593 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5594 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5598 glEnable(GL_SCISSOR_TEST);
5600 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5602 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5603 rect->x2 - rect->x1, rect->y2 - rect->y1);
5605 checkGLcall("glScissor");
5607 glDisable(GL_SCISSOR_TEST);
5609 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5611 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5614 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5615 glClear(GL_COLOR_BUFFER_BIT);
5616 checkGLcall("glClear");
5618 if (This->render_offscreen) {
5619 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5621 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5622 checkGLcall("glBindFramebuffer()");
5625 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5626 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5627 glDrawBuffer(GL_BACK);
5628 checkGLcall("glDrawBuffer()");
5632 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5634 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5636 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5638 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5639 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5640 return WINED3DERR_INVALIDCALL;
5643 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5644 color_fill_fbo(iface, pSurface, pRect, color);
5647 /* Just forward this to the DirectDraw blitting engine */
5648 memset(&BltFx, 0, sizeof(BltFx));
5649 BltFx.dwSize = sizeof(BltFx);
5650 BltFx.u5.dwFillColor = color;
5651 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5655 /* rendertarget and deptth stencil functions */
5656 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5660 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5661 return WINED3DERR_INVALIDCALL;
5664 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5665 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5666 /* Note inc ref on returned surface */
5667 if(*ppRenderTarget != NULL)
5668 IWineD3DSurface_AddRef(*ppRenderTarget);
5672 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5674 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5675 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5676 IWineD3DSwapChainImpl *Swapchain;
5679 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5681 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5682 if(hr != WINED3D_OK) {
5683 ERR("Can't get the swapchain\n");
5687 /* Make sure to release the swapchain */
5688 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5690 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5691 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5692 return WINED3DERR_INVALIDCALL;
5694 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5695 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5696 return WINED3DERR_INVALIDCALL;
5699 if(Swapchain->frontBuffer != Front) {
5700 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5702 if(Swapchain->frontBuffer)
5703 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5704 Swapchain->frontBuffer = Front;
5706 if(Swapchain->frontBuffer) {
5707 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5711 if(Back && !Swapchain->backBuffer) {
5712 /* We need memory for the back buffer array - only one back buffer this way */
5713 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5714 if(!Swapchain->backBuffer) {
5715 ERR("Out of memory\n");
5716 return E_OUTOFMEMORY;
5720 if(Swapchain->backBuffer[0] != Back) {
5721 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5723 /* What to do about the context here in the case of multithreading? Not sure.
5724 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5727 if(!Swapchain->backBuffer[0]) {
5728 /* GL was told to draw to the front buffer at creation,
5731 glDrawBuffer(GL_BACK);
5732 checkGLcall("glDrawBuffer(GL_BACK)");
5733 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5734 Swapchain->presentParms.BackBufferCount = 1;
5736 /* That makes problems - disable for now */
5737 /* glDrawBuffer(GL_FRONT); */
5738 checkGLcall("glDrawBuffer(GL_FRONT)");
5739 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5740 Swapchain->presentParms.BackBufferCount = 0;
5744 if(Swapchain->backBuffer[0])
5745 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5746 Swapchain->backBuffer[0] = Back;
5748 if(Swapchain->backBuffer[0]) {
5749 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5751 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5759 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5761 *ppZStencilSurface = This->depthStencilBuffer;
5762 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5764 if(*ppZStencilSurface != NULL) {
5765 /* Note inc ref on returned surface */
5766 IWineD3DSurface_AddRef(*ppZStencilSurface);
5771 /* TODO: Handle stencil attachments */
5772 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5774 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5776 TRACE("Set depth stencil to %p\n", depth_stencil);
5778 if (depth_stencil_impl) {
5779 if (depth_stencil_impl->current_renderbuffer) {
5780 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5781 checkGLcall("glFramebufferRenderbufferEXT()");
5783 IWineD3DBaseTextureImpl *texture_impl;
5784 GLenum texttarget, target;
5785 GLint old_binding = 0;
5787 texttarget = depth_stencil_impl->glDescription.target;
5788 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5789 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5791 IWineD3DSurface_PreLoad(depth_stencil);
5793 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5794 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5795 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5796 glBindTexture(target, old_binding);
5798 /* Update base texture states array */
5799 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5800 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5801 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5802 if (texture_impl->baseTexture.bindCount) {
5803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5806 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5809 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5810 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5811 checkGLcall("glFramebufferTexture2DEXT()");
5814 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5815 checkGLcall("glFramebufferTexture2DEXT()");
5819 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5821 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5823 TRACE("Set render target %u to %p\n", idx, render_target);
5826 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5827 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5829 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5830 checkGLcall("glFramebufferTexture2DEXT()");
5832 This->draw_buffers[idx] = GL_NONE;
5836 static void check_fbo_status(IWineD3DDevice *iface) {
5837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5840 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5841 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5842 TRACE("FBO complete\n");
5844 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5846 /* Dump the FBO attachments */
5847 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5848 IWineD3DSurfaceImpl *attachment;
5851 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5852 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5854 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5855 attachment->pow2Width, attachment->pow2Height);
5858 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5860 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5861 attachment->pow2Width, attachment->pow2Height);
5867 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5869 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5870 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5872 if (!ds_impl) return FALSE;
5874 if (ds_impl->current_renderbuffer) {
5875 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5876 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5879 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5880 rt_impl->pow2Height != ds_impl->pow2Height);
5883 void apply_fbo_state(IWineD3DDevice *iface) {
5884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5887 if (This->render_offscreen) {
5888 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5890 /* Apply render targets */
5891 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5892 IWineD3DSurface *render_target = This->render_targets[i];
5893 if (This->fbo_color_attachments[i] != render_target) {
5894 set_render_target_fbo(iface, i, render_target);
5895 This->fbo_color_attachments[i] = render_target;
5899 /* Apply depth targets */
5900 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5901 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5902 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5904 if (This->stencilBufferTarget) {
5905 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5907 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5908 This->fbo_depth_attachment = This->stencilBufferTarget;
5911 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5912 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5913 checkGLcall("glDrawBuffers()");
5915 glDrawBuffer(This->draw_buffers[0]);
5916 checkGLcall("glDrawBuffer()");
5919 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5922 check_fbo_status(iface);
5925 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5926 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5928 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5929 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5932 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5933 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5934 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5935 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5938 case WINED3DTEXF_LINEAR:
5939 gl_filter = GL_LINEAR;
5943 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5944 case WINED3DTEXF_NONE:
5945 case WINED3DTEXF_POINT:
5946 gl_filter = GL_NEAREST;
5950 /* Attach src surface to src fbo */
5951 src_swapchain = get_swapchain(src_surface);
5952 if (src_swapchain) {
5955 TRACE("Source surface %p is onscreen\n", src_surface);
5956 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5959 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5960 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5961 glReadBuffer(buffer);
5962 checkGLcall("glReadBuffer()");
5964 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5965 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5967 TRACE("Source surface %p is offscreen\n", src_surface);
5969 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5970 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5971 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5972 checkGLcall("glReadBuffer()");
5976 /* Attach dst surface to dst fbo */
5977 dst_swapchain = get_swapchain(dst_surface);
5978 if (dst_swapchain) {
5981 TRACE("Destination surface %p is onscreen\n", dst_surface);
5982 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5985 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5986 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5987 glDrawBuffer(buffer);
5988 checkGLcall("glDrawBuffer()");
5990 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5991 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5993 TRACE("Destination surface %p is offscreen\n", dst_surface);
5995 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5996 if(!src_swapchain) {
5997 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6001 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6002 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6003 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6004 checkGLcall("glDrawBuffer()");
6006 glDisable(GL_SCISSOR_TEST);
6007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6010 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6011 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6012 checkGLcall("glBlitFramebuffer()");
6014 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6015 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6016 checkGLcall("glBlitFramebuffer()");
6019 if (This->render_offscreen) {
6020 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6022 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6023 checkGLcall("glBindFramebuffer()");
6026 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6027 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6028 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6029 glDrawBuffer(GL_BACK);
6030 checkGLcall("glDrawBuffer()");
6035 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6037 WINED3DVIEWPORT viewport;
6039 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6041 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6042 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6043 return WINED3DERR_INVALIDCALL;
6046 /* MSDN says that null disables the render target
6047 but a device must always be associated with a render target
6048 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6050 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6053 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6054 FIXME("Trying to set render target 0 to NULL\n");
6055 return WINED3DERR_INVALIDCALL;
6057 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6058 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);
6059 return WINED3DERR_INVALIDCALL;
6062 /* If we are trying to set what we already have, don't bother */
6063 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6064 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6067 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6068 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6069 This->render_targets[RenderTargetIndex] = pRenderTarget;
6071 /* Render target 0 is special */
6072 if(RenderTargetIndex == 0) {
6073 /* Finally, reset the viewport as the MSDN states. */
6074 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6075 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6078 viewport.MaxZ = 1.0f;
6079 viewport.MinZ = 0.0f;
6080 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6081 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6082 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6086 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6088 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6089 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6091 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6096 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6098 HRESULT hr = WINED3D_OK;
6099 IWineD3DSurface *tmp;
6101 TRACE("(%p) Swapping z-buffer\n",This);
6103 if (pNewZStencil == This->stencilBufferTarget) {
6104 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6106 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6107 * depending on the renter target implementation being used.
6108 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6109 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6110 * stencil buffer and incure an extra memory overhead
6111 ******************************************************/
6113 tmp = This->stencilBufferTarget;
6114 This->stencilBufferTarget = pNewZStencil;
6115 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6116 /* should we be calling the parent or the wined3d surface? */
6117 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6118 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6121 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6122 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6132 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6133 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6135 /* TODO: the use of Impl is deprecated. */
6136 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6137 WINED3DLOCKED_RECT lockedRect;
6139 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6141 /* some basic validation checks */
6142 if(This->cursorTexture) {
6143 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6145 glDeleteTextures(1, &This->cursorTexture);
6147 This->cursorTexture = 0;
6150 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6151 This->haveHardwareCursor = TRUE;
6153 This->haveHardwareCursor = FALSE;
6156 WINED3DLOCKED_RECT rect;
6158 /* MSDN: Cursor must be A8R8G8B8 */
6159 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6160 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6161 return WINED3DERR_INVALIDCALL;
6164 /* MSDN: Cursor must be smaller than the display mode */
6165 if(pSur->currentDesc.Width > This->ddraw_width ||
6166 pSur->currentDesc.Height > This->ddraw_height) {
6167 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);
6168 return WINED3DERR_INVALIDCALL;
6171 if (!This->haveHardwareCursor) {
6172 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6174 /* Do not store the surface's pointer because the application may
6175 * release it after setting the cursor image. Windows doesn't
6176 * addref the set surface, so we can't do this either without
6177 * creating circular refcount dependencies. Copy out the gl texture
6180 This->cursorWidth = pSur->currentDesc.Width;
6181 This->cursorHeight = pSur->currentDesc.Height;
6182 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6184 const GlPixelFormatDesc *glDesc;
6185 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6186 char *mem, *bits = (char *)rect.pBits;
6187 GLint intfmt = glDesc->glInternal;
6188 GLint format = glDesc->glFormat;
6189 GLint type = glDesc->glType;
6190 INT height = This->cursorHeight;
6191 INT width = This->cursorWidth;
6192 INT bpp = tableEntry->bpp;
6195 /* Reformat the texture memory (pitch and width can be
6197 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6198 for(i = 0; i < height; i++)
6199 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6200 IWineD3DSurface_UnlockRect(pCursorBitmap);
6203 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6204 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6205 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6208 /* Make sure that a proper texture unit is selected */
6209 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6210 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6211 checkGLcall("glActiveTextureARB");
6213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6214 /* Create a new cursor texture */
6215 glGenTextures(1, &This->cursorTexture);
6216 checkGLcall("glGenTextures");
6217 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6218 checkGLcall("glBindTexture");
6219 /* Copy the bitmap memory into the cursor texture */
6220 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6221 HeapFree(GetProcessHeap(), 0, mem);
6222 checkGLcall("glTexImage2D");
6224 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6225 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6226 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6233 FIXME("A cursor texture was not returned.\n");
6234 This->cursorTexture = 0;
6239 /* Draw a hardware cursor */
6240 ICONINFO cursorInfo;
6242 /* Create and clear maskBits because it is not needed for
6243 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6245 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6246 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6247 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6248 WINED3DLOCK_NO_DIRTY_UPDATE |
6249 WINED3DLOCK_READONLY
6251 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6252 pSur->currentDesc.Height);
6254 cursorInfo.fIcon = FALSE;
6255 cursorInfo.xHotspot = XHotSpot;
6256 cursorInfo.yHotspot = YHotSpot;
6257 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6258 pSur->currentDesc.Height, 1,
6260 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6261 pSur->currentDesc.Height, 1,
6262 32, lockedRect.pBits);
6263 IWineD3DSurface_UnlockRect(pCursorBitmap);
6264 /* Create our cursor and clean up. */
6265 cursor = CreateIconIndirect(&cursorInfo);
6267 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6268 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6269 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6270 This->hardwareCursor = cursor;
6271 HeapFree(GetProcessHeap(), 0, maskBits);
6275 This->xHotSpot = XHotSpot;
6276 This->yHotSpot = YHotSpot;
6280 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6282 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6284 This->xScreenSpace = XScreenSpace;
6285 This->yScreenSpace = YScreenSpace;
6291 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6293 BOOL oldVisible = This->bCursorVisible;
6296 TRACE("(%p) : visible(%d)\n", This, bShow);
6299 * When ShowCursor is first called it should make the cursor appear at the OS's last
6300 * known cursor position. Because of this, some applications just repetitively call
6301 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6304 This->xScreenSpace = pt.x;
6305 This->yScreenSpace = pt.y;
6307 if (This->haveHardwareCursor) {
6308 This->bCursorVisible = bShow;
6310 SetCursor(This->hardwareCursor);
6316 if (This->cursorTexture)
6317 This->bCursorVisible = bShow;
6323 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6325 TRACE("(%p) : state (%u)\n", This, This->state);
6326 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6327 switch (This->state) {
6330 case WINED3DERR_DEVICELOST:
6332 ResourceList *resourceList = This->resources;
6333 while (NULL != resourceList) {
6334 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6335 return WINED3DERR_DEVICENOTRESET;
6336 resourceList = resourceList->next;
6338 return WINED3DERR_DEVICELOST;
6340 case WINED3DERR_DRIVERINTERNALERROR:
6341 return WINED3DERR_DRIVERINTERNALERROR;
6345 return WINED3DERR_DRIVERINTERNALERROR;
6349 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6351 /** FIXME: Resource tracking needs to be done,
6352 * The closes we can do to this is set the priorities of all managed textures low
6353 * and then reset them.
6354 ***********************************************************/
6355 FIXME("(%p) : stub\n", This);
6359 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6360 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6362 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6363 if(surface->Flags & SFLAG_DIBSECTION) {
6364 /* Release the DC */
6365 SelectObject(surface->hDC, surface->dib.holdbitmap);
6366 DeleteDC(surface->hDC);
6367 /* Release the DIB section */
6368 DeleteObject(surface->dib.DIBsection);
6369 surface->dib.bitmap_data = NULL;
6370 surface->resource.allocatedMemory = NULL;
6371 surface->Flags &= ~SFLAG_DIBSECTION;
6373 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6374 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6375 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6376 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6377 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6379 surface->pow2Width = surface->pow2Height = 1;
6380 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6381 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6383 if(surface->glDescription.textureName) {
6384 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6386 glDeleteTextures(1, &surface->glDescription.textureName);
6388 surface->glDescription.textureName = 0;
6389 surface->Flags &= ~SFLAG_CLIENT;
6391 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6392 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6393 surface->Flags |= SFLAG_NONPOW2;
6395 surface->Flags &= ~SFLAG_NONPOW2;
6397 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6398 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6401 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6403 IWineD3DSwapChainImpl *swapchain;
6405 BOOL DisplayModeChanged = FALSE;
6406 WINED3DDISPLAYMODE mode;
6407 TRACE("(%p)\n", This);
6409 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6411 ERR("Failed to get the first implicit swapchain\n");
6415 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6416 * on an existing gl context, so there's no real need for recreation.
6418 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6420 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6422 TRACE("New params:\n");
6423 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6424 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6425 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6426 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6427 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6428 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6429 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6430 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6431 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6432 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6433 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6434 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6435 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6437 /* No special treatment of these parameters. Just store them */
6438 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6439 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6440 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6441 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6443 /* What to do about these? */
6444 if(pPresentationParameters->BackBufferCount != 0 &&
6445 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6446 ERR("Cannot change the back buffer count yet\n");
6448 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6449 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6450 ERR("Cannot change the back buffer format yet\n");
6452 if(pPresentationParameters->hDeviceWindow != NULL &&
6453 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6454 ERR("Cannot change the device window yet\n");
6456 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6457 ERR("What do do about a changed auto depth stencil parameter?\n");
6460 if(pPresentationParameters->Windowed) {
6461 mode.Width = swapchain->orig_width;
6462 mode.Height = swapchain->orig_height;
6463 mode.RefreshRate = 0;
6464 mode.Format = swapchain->presentParms.BackBufferFormat;
6466 mode.Width = pPresentationParameters->BackBufferWidth;
6467 mode.Height = pPresentationParameters->BackBufferHeight;
6468 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6469 mode.Format = swapchain->presentParms.BackBufferFormat;
6472 /* Should Width == 800 && Height == 0 set 800x600? */
6473 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6474 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6475 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6482 vp.Width = pPresentationParameters->BackBufferWidth;
6483 vp.Height = pPresentationParameters->BackBufferHeight;
6487 if(!pPresentationParameters->Windowed) {
6488 DisplayModeChanged = TRUE;
6490 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6491 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6493 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6494 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6495 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6498 /* Now set the new viewport */
6499 IWineD3DDevice_SetViewport(iface, &vp);
6502 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6503 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6504 DisplayModeChanged) {
6506 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6507 if(!pPresentationParameters->Windowed) {
6508 IWineD3DDevice_SetFullscreen(iface, TRUE);
6511 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6513 /* Switching out of fullscreen mode? First set the original res, then change the window */
6514 if(pPresentationParameters->Windowed) {
6515 IWineD3DDevice_SetFullscreen(iface, FALSE);
6517 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6520 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6524 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6526 /** FIXME: always true at the moment **/
6527 if(!bEnableDialogs) {
6528 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6534 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6536 TRACE("(%p) : pParameters %p\n", This, pParameters);
6538 *pParameters = This->createParms;
6542 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6543 IWineD3DSwapChain *swapchain;
6544 HRESULT hrc = WINED3D_OK;
6546 TRACE("Relaying to swapchain\n");
6548 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6549 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6550 IWineD3DSwapChain_Release(swapchain);
6555 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6556 IWineD3DSwapChain *swapchain;
6557 HRESULT hrc = WINED3D_OK;
6559 TRACE("Relaying to swapchain\n");
6561 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6562 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6563 IWineD3DSwapChain_Release(swapchain);
6569 /** ********************************************************
6570 * Notification functions
6571 ** ********************************************************/
6572 /** This function must be called in the release of a resource when ref == 0,
6573 * the contents of resource must still be correct,
6574 * any handels to other resource held by the caller must be closed
6575 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6576 *****************************************************/
6577 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6579 ResourceList* resourceList;
6581 TRACE("(%p) : resource %p\n", This, resource);
6582 /* add a new texture to the frot of the linked list */
6583 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6584 resourceList->resource = resource;
6586 /* Get the old head */
6587 resourceList->next = This->resources;
6589 This->resources = resourceList;
6590 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6595 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6597 ResourceList* resourceList = NULL;
6598 ResourceList* previousResourceList = NULL;
6600 TRACE("(%p) : resource %p\n", This, resource);
6602 resourceList = This->resources;
6604 while (resourceList != NULL) {
6605 if(resourceList->resource == resource) break;
6606 previousResourceList = resourceList;
6607 resourceList = resourceList->next;
6610 if (resourceList == NULL) {
6611 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6614 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6616 /* make sure we don't leave a hole in the list */
6617 if (previousResourceList != NULL) {
6618 previousResourceList->next = resourceList->next;
6620 This->resources = resourceList->next;
6627 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6631 TRACE("(%p) : resource %p\n", This, resource);
6632 switch(IWineD3DResource_GetType(resource)){
6633 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6634 case WINED3DRTYPE_SURFACE: {
6637 /* Cleanup any FBO attachments if d3d is enabled */
6638 if(This->d3d_initialized) {
6639 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6640 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6641 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6642 set_render_target_fbo(iface, i, NULL);
6643 This->fbo_color_attachments[i] = NULL;
6646 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6647 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6648 set_depth_stencil_fbo(iface, NULL);
6649 This->fbo_depth_attachment = NULL;
6655 case WINED3DRTYPE_TEXTURE:
6656 case WINED3DRTYPE_CUBETEXTURE:
6657 case WINED3DRTYPE_VOLUMETEXTURE:
6658 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6659 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6660 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6661 This->stateBlock->textures[counter] = NULL;
6663 if (This->updateStateBlock != This->stateBlock ){
6664 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6665 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6666 This->updateStateBlock->textures[counter] = NULL;
6671 case WINED3DRTYPE_VOLUME:
6672 /* TODO: nothing really? */
6674 case WINED3DRTYPE_VERTEXBUFFER:
6675 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6678 TRACE("Cleaning up stream pointers\n");
6680 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6681 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6682 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6684 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6685 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6686 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6687 This->updateStateBlock->streamSource[streamNumber] = 0;
6688 /* Set changed flag? */
6691 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) */
6692 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6693 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6694 This->stateBlock->streamSource[streamNumber] = 0;
6697 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6698 else { /* This shouldn't happen */
6699 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6706 case WINED3DRTYPE_INDEXBUFFER:
6707 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6708 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6709 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6710 This->updateStateBlock->pIndexData = NULL;
6713 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6714 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6715 This->stateBlock->pIndexData = NULL;
6721 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6726 /* Remove the resoruce from the resourceStore */
6727 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6729 TRACE("Resource released\n");
6733 /**********************************************************
6734 * IWineD3DDevice VTbl follows
6735 **********************************************************/
6737 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6739 /*** IUnknown methods ***/
6740 IWineD3DDeviceImpl_QueryInterface,
6741 IWineD3DDeviceImpl_AddRef,
6742 IWineD3DDeviceImpl_Release,
6743 /*** IWineD3DDevice methods ***/
6744 IWineD3DDeviceImpl_GetParent,
6745 /*** Creation methods**/
6746 IWineD3DDeviceImpl_CreateVertexBuffer,
6747 IWineD3DDeviceImpl_CreateIndexBuffer,
6748 IWineD3DDeviceImpl_CreateStateBlock,
6749 IWineD3DDeviceImpl_CreateSurface,
6750 IWineD3DDeviceImpl_CreateTexture,
6751 IWineD3DDeviceImpl_CreateVolumeTexture,
6752 IWineD3DDeviceImpl_CreateVolume,
6753 IWineD3DDeviceImpl_CreateCubeTexture,
6754 IWineD3DDeviceImpl_CreateQuery,
6755 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6756 IWineD3DDeviceImpl_CreateVertexDeclaration,
6757 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6758 IWineD3DDeviceImpl_CreateVertexShader,
6759 IWineD3DDeviceImpl_CreatePixelShader,
6760 IWineD3DDeviceImpl_CreatePalette,
6761 /*** Odd functions **/
6762 IWineD3DDeviceImpl_Init3D,
6763 IWineD3DDeviceImpl_Uninit3D,
6764 IWineD3DDeviceImpl_SetFullscreen,
6765 IWineD3DDeviceImpl_SetMultithreaded,
6766 IWineD3DDeviceImpl_EvictManagedResources,
6767 IWineD3DDeviceImpl_GetAvailableTextureMem,
6768 IWineD3DDeviceImpl_GetBackBuffer,
6769 IWineD3DDeviceImpl_GetCreationParameters,
6770 IWineD3DDeviceImpl_GetDeviceCaps,
6771 IWineD3DDeviceImpl_GetDirect3D,
6772 IWineD3DDeviceImpl_GetDisplayMode,
6773 IWineD3DDeviceImpl_SetDisplayMode,
6774 IWineD3DDeviceImpl_GetHWND,
6775 IWineD3DDeviceImpl_SetHWND,
6776 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6777 IWineD3DDeviceImpl_GetRasterStatus,
6778 IWineD3DDeviceImpl_GetSwapChain,
6779 IWineD3DDeviceImpl_Reset,
6780 IWineD3DDeviceImpl_SetDialogBoxMode,
6781 IWineD3DDeviceImpl_SetCursorProperties,
6782 IWineD3DDeviceImpl_SetCursorPosition,
6783 IWineD3DDeviceImpl_ShowCursor,
6784 IWineD3DDeviceImpl_TestCooperativeLevel,
6785 /*** Getters and setters **/
6786 IWineD3DDeviceImpl_SetClipPlane,
6787 IWineD3DDeviceImpl_GetClipPlane,
6788 IWineD3DDeviceImpl_SetClipStatus,
6789 IWineD3DDeviceImpl_GetClipStatus,
6790 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6791 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6792 IWineD3DDeviceImpl_SetDepthStencilSurface,
6793 IWineD3DDeviceImpl_GetDepthStencilSurface,
6794 IWineD3DDeviceImpl_SetFVF,
6795 IWineD3DDeviceImpl_GetFVF,
6796 IWineD3DDeviceImpl_SetGammaRamp,
6797 IWineD3DDeviceImpl_GetGammaRamp,
6798 IWineD3DDeviceImpl_SetIndices,
6799 IWineD3DDeviceImpl_GetIndices,
6800 IWineD3DDeviceImpl_SetBaseVertexIndex,
6801 IWineD3DDeviceImpl_GetBaseVertexIndex,
6802 IWineD3DDeviceImpl_SetLight,
6803 IWineD3DDeviceImpl_GetLight,
6804 IWineD3DDeviceImpl_SetLightEnable,
6805 IWineD3DDeviceImpl_GetLightEnable,
6806 IWineD3DDeviceImpl_SetMaterial,
6807 IWineD3DDeviceImpl_GetMaterial,
6808 IWineD3DDeviceImpl_SetNPatchMode,
6809 IWineD3DDeviceImpl_GetNPatchMode,
6810 IWineD3DDeviceImpl_SetPaletteEntries,
6811 IWineD3DDeviceImpl_GetPaletteEntries,
6812 IWineD3DDeviceImpl_SetPixelShader,
6813 IWineD3DDeviceImpl_GetPixelShader,
6814 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6815 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6816 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6817 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6818 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6819 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6820 IWineD3DDeviceImpl_SetRenderState,
6821 IWineD3DDeviceImpl_GetRenderState,
6822 IWineD3DDeviceImpl_SetRenderTarget,
6823 IWineD3DDeviceImpl_GetRenderTarget,
6824 IWineD3DDeviceImpl_SetFrontBackBuffers,
6825 IWineD3DDeviceImpl_SetSamplerState,
6826 IWineD3DDeviceImpl_GetSamplerState,
6827 IWineD3DDeviceImpl_SetScissorRect,
6828 IWineD3DDeviceImpl_GetScissorRect,
6829 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6830 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6831 IWineD3DDeviceImpl_SetStreamSource,
6832 IWineD3DDeviceImpl_GetStreamSource,
6833 IWineD3DDeviceImpl_SetStreamSourceFreq,
6834 IWineD3DDeviceImpl_GetStreamSourceFreq,
6835 IWineD3DDeviceImpl_SetTexture,
6836 IWineD3DDeviceImpl_GetTexture,
6837 IWineD3DDeviceImpl_SetTextureStageState,
6838 IWineD3DDeviceImpl_GetTextureStageState,
6839 IWineD3DDeviceImpl_SetTransform,
6840 IWineD3DDeviceImpl_GetTransform,
6841 IWineD3DDeviceImpl_SetVertexDeclaration,
6842 IWineD3DDeviceImpl_GetVertexDeclaration,
6843 IWineD3DDeviceImpl_SetVertexShader,
6844 IWineD3DDeviceImpl_GetVertexShader,
6845 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6846 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6847 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6848 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6849 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6850 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6851 IWineD3DDeviceImpl_SetViewport,
6852 IWineD3DDeviceImpl_GetViewport,
6853 IWineD3DDeviceImpl_MultiplyTransform,
6854 IWineD3DDeviceImpl_ValidateDevice,
6855 IWineD3DDeviceImpl_ProcessVertices,
6856 /*** State block ***/
6857 IWineD3DDeviceImpl_BeginStateBlock,
6858 IWineD3DDeviceImpl_EndStateBlock,
6859 /*** Scene management ***/
6860 IWineD3DDeviceImpl_BeginScene,
6861 IWineD3DDeviceImpl_EndScene,
6862 IWineD3DDeviceImpl_Present,
6863 IWineD3DDeviceImpl_Clear,
6865 IWineD3DDeviceImpl_DrawPrimitive,
6866 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6867 IWineD3DDeviceImpl_DrawPrimitiveUP,
6868 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6869 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6870 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6871 IWineD3DDeviceImpl_DrawRectPatch,
6872 IWineD3DDeviceImpl_DrawTriPatch,
6873 IWineD3DDeviceImpl_DeletePatch,
6874 IWineD3DDeviceImpl_ColorFill,
6875 IWineD3DDeviceImpl_UpdateTexture,
6876 IWineD3DDeviceImpl_UpdateSurface,
6877 IWineD3DDeviceImpl_GetFrontBufferData,
6878 /*** object tracking ***/
6879 IWineD3DDeviceImpl_ResourceReleased
6883 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6884 WINED3DRS_ALPHABLENDENABLE ,
6885 WINED3DRS_ALPHAFUNC ,
6886 WINED3DRS_ALPHAREF ,
6887 WINED3DRS_ALPHATESTENABLE ,
6889 WINED3DRS_COLORWRITEENABLE ,
6890 WINED3DRS_DESTBLEND ,
6891 WINED3DRS_DITHERENABLE ,
6892 WINED3DRS_FILLMODE ,
6893 WINED3DRS_FOGDENSITY ,
6895 WINED3DRS_FOGSTART ,
6896 WINED3DRS_LASTPIXEL ,
6897 WINED3DRS_SHADEMODE ,
6898 WINED3DRS_SRCBLEND ,
6899 WINED3DRS_STENCILENABLE ,
6900 WINED3DRS_STENCILFAIL ,
6901 WINED3DRS_STENCILFUNC ,
6902 WINED3DRS_STENCILMASK ,
6903 WINED3DRS_STENCILPASS ,
6904 WINED3DRS_STENCILREF ,
6905 WINED3DRS_STENCILWRITEMASK ,
6906 WINED3DRS_STENCILZFAIL ,
6907 WINED3DRS_TEXTUREFACTOR ,
6918 WINED3DRS_ZWRITEENABLE
6921 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6922 WINED3DTSS_ADDRESSW ,
6923 WINED3DTSS_ALPHAARG0 ,
6924 WINED3DTSS_ALPHAARG1 ,
6925 WINED3DTSS_ALPHAARG2 ,
6926 WINED3DTSS_ALPHAOP ,
6927 WINED3DTSS_BUMPENVLOFFSET ,
6928 WINED3DTSS_BUMPENVLSCALE ,
6929 WINED3DTSS_BUMPENVMAT00 ,
6930 WINED3DTSS_BUMPENVMAT01 ,
6931 WINED3DTSS_BUMPENVMAT10 ,
6932 WINED3DTSS_BUMPENVMAT11 ,
6933 WINED3DTSS_COLORARG0 ,
6934 WINED3DTSS_COLORARG1 ,
6935 WINED3DTSS_COLORARG2 ,
6936 WINED3DTSS_COLOROP ,
6937 WINED3DTSS_RESULTARG ,
6938 WINED3DTSS_TEXCOORDINDEX ,
6939 WINED3DTSS_TEXTURETRANSFORMFLAGS
6942 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6943 WINED3DSAMP_ADDRESSU ,
6944 WINED3DSAMP_ADDRESSV ,
6945 WINED3DSAMP_ADDRESSW ,
6946 WINED3DSAMP_BORDERCOLOR ,
6947 WINED3DSAMP_MAGFILTER ,
6948 WINED3DSAMP_MINFILTER ,
6949 WINED3DSAMP_MIPFILTER ,
6950 WINED3DSAMP_MIPMAPLODBIAS ,
6951 WINED3DSAMP_MAXMIPLEVEL ,
6952 WINED3DSAMP_MAXANISOTROPY ,
6953 WINED3DSAMP_SRGBTEXTURE ,
6954 WINED3DSAMP_ELEMENTINDEX
6957 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6959 WINED3DRS_AMBIENTMATERIALSOURCE ,
6960 WINED3DRS_CLIPPING ,
6961 WINED3DRS_CLIPPLANEENABLE ,
6962 WINED3DRS_COLORVERTEX ,
6963 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6964 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6965 WINED3DRS_FOGDENSITY ,
6967 WINED3DRS_FOGSTART ,
6968 WINED3DRS_FOGTABLEMODE ,
6969 WINED3DRS_FOGVERTEXMODE ,
6970 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6971 WINED3DRS_LIGHTING ,
6972 WINED3DRS_LOCALVIEWER ,
6973 WINED3DRS_MULTISAMPLEANTIALIAS ,
6974 WINED3DRS_MULTISAMPLEMASK ,
6975 WINED3DRS_NORMALIZENORMALS ,
6976 WINED3DRS_PATCHEDGESTYLE ,
6977 WINED3DRS_POINTSCALE_A ,
6978 WINED3DRS_POINTSCALE_B ,
6979 WINED3DRS_POINTSCALE_C ,
6980 WINED3DRS_POINTSCALEENABLE ,
6981 WINED3DRS_POINTSIZE ,
6982 WINED3DRS_POINTSIZE_MAX ,
6983 WINED3DRS_POINTSIZE_MIN ,
6984 WINED3DRS_POINTSPRITEENABLE ,
6985 WINED3DRS_RANGEFOGENABLE ,
6986 WINED3DRS_SPECULARMATERIALSOURCE ,
6987 WINED3DRS_TWEENFACTOR ,
6988 WINED3DRS_VERTEXBLEND ,
6989 WINED3DRS_CULLMODE ,
6993 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6994 WINED3DTSS_TEXCOORDINDEX ,
6995 WINED3DTSS_TEXTURETRANSFORMFLAGS
6998 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6999 WINED3DSAMP_DMAPOFFSET
7002 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7003 DWORD rep = StateTable[state].representative;
7007 WineD3DContext *context;
7010 for(i = 0; i < This->numContexts; i++) {
7011 context = This->contexts[i];
7012 if(isStateDirty(context, rep)) continue;
7014 context->dirtyArray[context->numDirtyEntries++] = rep;
7017 context->isStateDirty[idx] |= (1 << shift);