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-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 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; \
75 object->baseShader.ref = 1; \
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 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 /* TODO: Clean up all the surfaces and textures! */
167 /* NOTE: You must release the parent if the object was created via a callback
168 ** ***************************/
170 if (!list_empty(&This->resources)) {
171 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
172 dumpResources(&This->resources);
175 if(This->contexts) ERR("Context array not freed!\n");
176 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
177 This->haveHardwareCursor = FALSE;
179 IWineD3D_Release(This->wineD3D);
180 This->wineD3D = NULL;
181 HeapFree(GetProcessHeap(), 0, This);
182 TRACE("Freed device %p\n", This);
188 /**********************************************************
189 * IWineD3DDevice implementation follows
190 **********************************************************/
191 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
193 *pParent = This->parent;
194 IUnknown_AddRef(This->parent);
198 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
199 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
202 IWineD3DVertexBufferImpl *object;
203 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
204 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
208 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
209 *ppVertexBuffer = NULL;
210 return WINED3DERR_INVALIDCALL;
211 } else if(Pool == WINED3DPOOL_SCRATCH) {
212 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
213 * anyway, SCRATCH vertex buffers aren't usable anywhere
215 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
216 *ppVertexBuffer = NULL;
217 return WINED3DERR_INVALIDCALL;
220 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
222 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
223 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
227 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
228 * drawStridedFast (half-life 2).
230 * Basically converting the vertices in the buffer is quite expensive, and observations
231 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
232 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
234 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
235 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
236 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
237 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
239 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
240 * more. In this call we can convert dx7 buffers too.
242 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
243 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
244 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
245 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
246 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
247 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
248 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
249 } else if(dxVersion <= 7 && conv) {
250 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
252 object->Flags |= VBFLAG_CREATEVBO;
257 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
258 GLenum error, glUsage;
259 TRACE("Creating VBO for Index Buffer %p\n", object);
261 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
262 * restored on the next draw
264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
266 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
267 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
272 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
273 error = glGetError();
274 if(error != GL_NO_ERROR || object->vbo == 0) {
275 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
279 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
280 error = glGetError();
281 if(error != GL_NO_ERROR) {
282 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
286 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
287 * copy no readback will be needed
289 glUsage = GL_STATIC_DRAW_ARB;
290 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
291 error = glGetError();
292 if(error != GL_NO_ERROR) {
293 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
297 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
301 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
302 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
307 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
308 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
309 HANDLE *sharedHandle, IUnknown *parent) {
310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
311 IWineD3DIndexBufferImpl *object;
312 TRACE("(%p) Creating index buffer\n", This);
314 /* Allocate the storage for the device */
315 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
317 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
318 CreateIndexBufferVBO(This, object);
321 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
322 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
323 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
328 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
331 IWineD3DStateBlockImpl *object;
335 D3DCREATEOBJECTINSTANCE(object, StateBlock)
336 object->blockType = Type;
338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
339 list_init(&object->lightMap[i]);
342 /* Special case - Used during initialization to produce a placeholder stateblock
343 so other functions called can update a state block */
344 if (Type == WINED3DSBT_INIT) {
345 /* Don't bother increasing the reference count otherwise a device will never
346 be freed due to circular dependencies */
350 temp_result = allocate_shader_constants(object);
351 if (WINED3D_OK != temp_result)
354 /* Otherwise, might as well set the whole state block to the appropriate values */
355 if (This->stateBlock != NULL)
356 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
358 memset(object->streamFreq, 1, sizeof(object->streamFreq));
360 /* Reset the ref and type after kludging it */
361 object->wineD3DDevice = This;
363 object->blockType = Type;
365 TRACE("Updating changed flags appropriate for type %d\n", Type);
367 if (Type == WINED3DSBT_ALL) {
369 TRACE("ALL => Pretend everything has changed\n");
370 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
372 /* Lights are not part of the changed / set structure */
373 for(j = 0; j < LIGHTMAP_SIZE; j++) {
375 LIST_FOR_EACH(e, &object->lightMap[j]) {
376 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
377 light->changed = TRUE;
378 light->enabledChanged = TRUE;
381 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
382 object->contained_render_states[j - 1] = j;
384 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
385 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
386 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
387 object->contained_transform_states[j - 1] = j;
389 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
390 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
391 object->contained_vs_consts_f[j] = j;
393 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
394 for(j = 0; j < MAX_CONST_I; j++) {
395 object->contained_vs_consts_i[j] = j;
397 object->num_contained_vs_consts_i = MAX_CONST_I;
398 for(j = 0; j < MAX_CONST_B; j++) {
399 object->contained_vs_consts_b[j] = j;
401 object->num_contained_vs_consts_b = MAX_CONST_B;
402 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
403 object->contained_ps_consts_f[j] = j;
405 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_ps_consts_i[j] = j;
409 object->num_contained_ps_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_ps_consts_b[j] = j;
413 object->num_contained_ps_consts_b = MAX_CONST_B;
414 for(i = 0; i < MAX_TEXTURES; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
416 object->contained_tss_states[object->num_contained_tss_states].stage = i;
417 object->contained_tss_states[object->num_contained_tss_states].state = j;
418 object->num_contained_tss_states++;
421 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
422 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
423 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
424 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
425 object->num_contained_sampler_states++;
429 for(i = 0; i < MAX_STREAMS; i++) {
430 if(object->streamSource[i]) {
431 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
434 if(object->pIndexData) {
435 IWineD3DIndexBuffer_AddRef(object->pIndexData);
437 if(object->vertexShader) {
438 IWineD3DVertexShader_AddRef(object->vertexShader);
440 if(object->pixelShader) {
441 IWineD3DPixelShader_AddRef(object->pixelShader);
444 } else if (Type == WINED3DSBT_PIXELSTATE) {
446 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
447 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
449 object->changed.pixelShader = TRUE;
451 /* Pixel Shader Constants */
452 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
453 object->contained_ps_consts_f[i] = i;
454 object->changed.pixelShaderConstantsF[i] = TRUE;
456 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
457 for (i = 0; i < MAX_CONST_B; ++i) {
458 object->contained_ps_consts_b[i] = i;
459 object->changed.pixelShaderConstantsB[i] = TRUE;
461 object->num_contained_ps_consts_b = MAX_CONST_B;
462 for (i = 0; i < MAX_CONST_I; ++i) {
463 object->contained_ps_consts_i[i] = i;
464 object->changed.pixelShaderConstantsI[i] = TRUE;
466 object->num_contained_ps_consts_i = MAX_CONST_I;
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
469 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
470 object->contained_render_states[i] = SavedPixelStates_R[i];
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
476 object->contained_tss_states[object->num_contained_tss_states].stage = j;
477 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
478 object->num_contained_tss_states++;
481 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
482 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
483 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
484 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
485 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
486 object->num_contained_sampler_states++;
489 if(object->pixelShader) {
490 IWineD3DPixelShader_AddRef(object->pixelShader);
493 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
494 * on them. This makes releasing the buffer easier
496 for(i = 0; i < MAX_STREAMS; i++) {
497 object->streamSource[i] = NULL;
499 object->pIndexData = NULL;
500 object->vertexShader = NULL;
502 } else if (Type == WINED3DSBT_VERTEXSTATE) {
504 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.vertexShader = TRUE;
509 /* Vertex Shader Constants */
510 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
511 object->changed.vertexShaderConstantsF[i] = TRUE;
512 object->contained_vs_consts_f[i] = i;
514 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
515 for (i = 0; i < MAX_CONST_B; ++i) {
516 object->changed.vertexShaderConstantsB[i] = TRUE;
517 object->contained_vs_consts_b[i] = i;
519 object->num_contained_vs_consts_b = MAX_CONST_B;
520 for (i = 0; i < MAX_CONST_I; ++i) {
521 object->changed.vertexShaderConstantsI[i] = TRUE;
522 object->contained_vs_consts_i[i] = i;
524 object->num_contained_vs_consts_i = MAX_CONST_I;
525 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
526 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
527 object->contained_render_states[i] = SavedVertexStates_R[i];
529 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
530 for (j = 0; j < MAX_TEXTURES; j++) {
531 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
532 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
533 object->contained_tss_states[object->num_contained_tss_states].stage = j;
534 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
535 object->num_contained_tss_states++;
538 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
539 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
540 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
541 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
542 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
543 object->num_contained_sampler_states++;
547 for(j = 0; j < LIGHTMAP_SIZE; j++) {
549 LIST_FOR_EACH(e, &object->lightMap[j]) {
550 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
551 light->changed = TRUE;
552 light->enabledChanged = TRUE;
556 for(i = 0; i < MAX_STREAMS; i++) {
557 if(object->streamSource[i]) {
558 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 object->pIndexData = NULL;
565 object->pixelShader = NULL;
567 FIXME("Unrecognized state block type %d\n", Type);
570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
574 /* ************************************
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 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.
583 ******************************** */
585 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) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int Size = 1;
589 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
590 TRACE("(%p) Create surface\n",This);
592 /** FIXME: Check ranges on the inputs are valid
595 * [in] Quality level. The valid range is between zero and one less than the level
596 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
597 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
598 * values of paired render targets, depth stencil surfaces, and the MultiSample type
600 *******************************/
605 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
607 * If this flag is set, the contents of the depth stencil buffer will be
608 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
609 * with a different depth surface.
611 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
612 ***************************/
614 if(MultisampleQuality > 0) {
615 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
616 MultisampleQuality=0;
619 /** FIXME: Check that the format is supported
621 *******************************/
623 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
624 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
626 *********************************/
627 if (WINED3DFMT_UNKNOWN == Format) {
629 } else if (Format == WINED3DFMT_DXT1) {
630 /* DXT1 is half byte per pixel */
631 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
633 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
634 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
635 Format == WINED3DFMT_ATI2N) {
636 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
638 /* The pitch is a multiple of 4 bytes */
639 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
643 /** Create and initialise the surface resource **/
644 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
645 /* "Standalone" surface */
646 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
648 object->currentDesc.Width = Width;
649 object->currentDesc.Height = Height;
650 object->currentDesc.MultiSampleType = MultiSample;
651 object->currentDesc.MultiSampleQuality = MultisampleQuality;
652 object->glDescription.level = Level;
653 list_init(&object->overlays);
656 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
657 object->Flags |= Discard ? SFLAG_DISCARD : 0;
658 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
659 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
662 if (WINED3DFMT_UNKNOWN != Format) {
663 object->bytesPerPixel = tableEntry->bpp;
665 object->bytesPerPixel = 0;
668 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
670 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
672 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
673 * this function is too deep to need to care about things like this.
674 * Levels need to be checked too, and possibly Type since they all affect what can be done.
675 * ****************************************/
677 case WINED3DPOOL_SCRATCH:
679 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
680 "which are mutually exclusive, setting lockable to TRUE\n");
683 case WINED3DPOOL_SYSTEMMEM:
684 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
685 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
686 case WINED3DPOOL_MANAGED:
687 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
688 "Usage of DYNAMIC which are mutually exclusive, not doing "
689 "anything just telling you.\n");
691 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
692 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
693 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
694 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
697 FIXME("(%p) Unknown pool %d\n", This, Pool);
701 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
702 FIXME("Trying to create a render target that isn't in the default pool\n");
705 /* mark the texture as dirty so that it gets loaded first time around*/
706 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
707 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
708 This, Width, Height, Format, debug_d3dformat(Format),
709 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
711 /* Look at the implementation and set the correct Vtable */
714 /* Check if a 3D adapter is available when creating gl surfaces */
716 ERR("OpenGL surfaces are not available without opengl\n");
717 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
718 HeapFree(GetProcessHeap(), 0, object);
719 return WINED3DERR_NOTAVAILABLE;
724 object->lpVtbl = &IWineGDISurface_Vtbl;
728 /* To be sure to catch this */
729 ERR("Unknown requested surface implementation %d!\n", Impl);
730 IWineD3DSurface_Release((IWineD3DSurface *) object);
731 return WINED3DERR_INVALIDCALL;
734 list_init(&object->renderbuffers);
736 /* Call the private setup routine */
737 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
741 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
742 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
743 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
744 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
747 IWineD3DTextureImpl *object;
752 unsigned int pow2Width;
753 unsigned int pow2Height;
754 const GlPixelFormatDesc *glDesc;
755 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
757 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
758 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
759 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
761 /* TODO: It should only be possible to create textures for formats
762 that are reported as supported */
763 if (WINED3DFMT_UNKNOWN >= Format) {
764 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
765 return WINED3DERR_INVALIDCALL;
768 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
769 D3DINITIALIZEBASETEXTURE(object->baseTexture);
770 object->width = Width;
771 object->height = Height;
773 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
774 object->baseTexture.minMipLookup = &minMipLookup;
775 object->baseTexture.magLookup = &magLookup;
777 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
778 object->baseTexture.magLookup = &magLookup_noFilter;
781 /** Non-power2 support **/
782 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
786 /* Find the nearest pow2 match */
787 pow2Width = pow2Height = 1;
788 while (pow2Width < Width) pow2Width <<= 1;
789 while (pow2Height < Height) pow2Height <<= 1;
791 if(pow2Width != Width || pow2Height != Height) {
793 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
794 HeapFree(GetProcessHeap(), 0, object);
796 return WINED3DERR_INVALIDCALL;
803 /** FIXME: add support for real non-power-two if it's provided by the video card **/
804 /* Precalculated scaling for 'faked' non power of two texture coords.
805 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
806 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
807 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
809 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
810 object->baseTexture.pow2Matrix[0] = 1.0;
811 object->baseTexture.pow2Matrix[5] = 1.0;
812 object->baseTexture.pow2Matrix[10] = 1.0;
813 object->baseTexture.pow2Matrix[15] = 1.0;
814 object->target = GL_TEXTURE_2D;
815 object->cond_np2 = TRUE;
818 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
819 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
820 (Width != pow2Width || Height != pow2Height) &&
821 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
823 object->baseTexture.pow2Matrix[0] = (float)Width;
824 object->baseTexture.pow2Matrix[5] = (float)Height;
825 object->baseTexture.pow2Matrix[10] = 1.0;
826 object->baseTexture.pow2Matrix[15] = 1.0;
827 object->target = GL_TEXTURE_RECTANGLE_ARB;
828 object->cond_np2 = TRUE;
829 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
831 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
832 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_2D;
836 object->cond_np2 = FALSE;
838 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
840 /* Calculate levels for mip mapping */
841 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
842 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
843 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
847 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
848 return WINED3DERR_INVALIDCALL;
850 object->baseTexture.levels = 1;
851 } else if (Levels == 0) {
852 TRACE("calculating levels %d\n", object->baseTexture.levels);
853 object->baseTexture.levels++;
856 while (tmpW > 1 || tmpH > 1) {
857 tmpW = max(1, tmpW >> 1);
858 tmpH = max(1, tmpH >> 1);
859 object->baseTexture.levels++;
861 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
864 /* Generate all the surfaces */
867 for (i = 0; i < object->baseTexture.levels; i++)
869 /* use the callback to create the texture surface */
870 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
871 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
872 FIXME("Failed to create surface %p\n", object);
874 object->surfaces[i] = NULL;
875 IWineD3DTexture_Release((IWineD3DTexture *)object);
881 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
882 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
883 /* calculate the next mipmap level */
884 tmpW = max(1, tmpW >> 1);
885 tmpH = max(1, tmpH >> 1);
887 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
889 TRACE("(%p) : Created texture %p\n", This, object);
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
894 UINT Width, UINT Height, UINT Depth,
895 UINT Levels, DWORD Usage,
896 WINED3DFORMAT Format, WINED3DPOOL Pool,
897 IWineD3DVolumeTexture **ppVolumeTexture,
898 HANDLE *pSharedHandle, IUnknown *parent,
899 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
902 IWineD3DVolumeTextureImpl *object;
907 const GlPixelFormatDesc *glDesc;
909 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
911 /* TODO: It should only be possible to create textures for formats
912 that are reported as supported */
913 if (WINED3DFMT_UNKNOWN >= Format) {
914 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
915 return WINED3DERR_INVALIDCALL;
917 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
918 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
919 return WINED3DERR_INVALIDCALL;
922 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
923 D3DINITIALIZEBASETEXTURE(object->baseTexture);
925 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
926 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
928 object->width = Width;
929 object->height = Height;
930 object->depth = Depth;
932 /* Is NP2 support for volumes needed? */
933 object->baseTexture.pow2Matrix[ 0] = 1.0;
934 object->baseTexture.pow2Matrix[ 5] = 1.0;
935 object->baseTexture.pow2Matrix[10] = 1.0;
936 object->baseTexture.pow2Matrix[15] = 1.0;
938 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
939 object->baseTexture.minMipLookup = &minMipLookup;
940 object->baseTexture.magLookup = &magLookup;
942 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
943 object->baseTexture.magLookup = &magLookup_noFilter;
946 /* Calculate levels for mip mapping */
947 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
948 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
949 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
950 return WINED3DERR_INVALIDCALL;
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
957 } else if (Levels == 0) {
958 object->baseTexture.levels++;
962 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
963 tmpW = max(1, tmpW >> 1);
964 tmpH = max(1, tmpH >> 1);
965 tmpD = max(1, tmpD >> 1);
966 object->baseTexture.levels++;
968 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
971 /* Generate all the surfaces */
976 for (i = 0; i < object->baseTexture.levels; i++)
979 /* Create the volume */
980 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
981 &object->volumes[i], pSharedHandle);
984 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
985 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
986 *ppVolumeTexture = NULL;
990 /* Set its container to this object */
991 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
993 /* calculate the next mipmap level */
994 tmpW = max(1, tmpW >> 1);
995 tmpH = max(1, tmpH >> 1);
996 tmpD = max(1, tmpD >> 1);
998 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1000 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1001 TRACE("(%p) : Created volume texture %p\n", This, object);
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1006 UINT Width, UINT Height, UINT Depth,
1008 WINED3DFORMAT Format, WINED3DPOOL Pool,
1009 IWineD3DVolume** ppVolume,
1010 HANDLE* pSharedHandle, IUnknown *parent) {
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1014 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1016 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1017 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1018 return WINED3DERR_INVALIDCALL;
1021 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1023 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1024 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1026 object->currentDesc.Width = Width;
1027 object->currentDesc.Height = Height;
1028 object->currentDesc.Depth = Depth;
1029 object->bytesPerPixel = formatDesc->bpp;
1031 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1032 object->lockable = TRUE;
1033 object->locked = FALSE;
1034 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1035 object->dirty = TRUE;
1037 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1040 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1041 UINT Levels, DWORD Usage,
1042 WINED3DFORMAT Format, WINED3DPOOL Pool,
1043 IWineD3DCubeTexture **ppCubeTexture,
1044 HANDLE *pSharedHandle, IUnknown *parent,
1045 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1048 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1052 unsigned int pow2EdgeLength = EdgeLength;
1053 const GlPixelFormatDesc *glDesc;
1054 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1056 /* TODO: It should only be possible to create textures for formats
1057 that are reported as supported */
1058 if (WINED3DFMT_UNKNOWN >= Format) {
1059 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1060 return WINED3DERR_INVALIDCALL;
1063 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1064 WARN("(%p) : Tried to create not supported cube texture\n", This);
1065 return WINED3DERR_INVALIDCALL;
1068 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1069 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1071 TRACE("(%p) Create Cube Texture\n", This);
1073 /** Non-power2 support **/
1075 /* Find the nearest pow2 match */
1077 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1079 object->edgeLength = EdgeLength;
1080 /* TODO: support for native non-power 2 */
1081 /* Precalculated scaling for 'faked' non power of two texture coords */
1082 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1083 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 object->baseTexture.pow2Matrix[15] = 1.0;
1087 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1088 object->baseTexture.minMipLookup = &minMipLookup;
1089 object->baseTexture.magLookup = &magLookup;
1091 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1092 object->baseTexture.magLookup = &magLookup_noFilter;
1095 /* Calculate levels for mip mapping */
1096 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1097 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1098 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1099 HeapFree(GetProcessHeap(), 0, object);
1100 *ppCubeTexture = NULL;
1102 return WINED3DERR_INVALIDCALL;
1105 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1109 return WINED3DERR_INVALIDCALL;
1112 } else if (Levels == 0) {
1113 object->baseTexture.levels++;
1116 tmpW = max(1, tmpW >> 1);
1117 object->baseTexture.levels++;
1119 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1122 /* Generate all the surfaces */
1124 for (i = 0; i < object->baseTexture.levels; i++) {
1126 /* Create the 6 faces */
1127 for (j = 0; j < 6; j++) {
1129 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1130 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1132 if(hr!= WINED3D_OK) {
1136 for (l = 0; l < j; l++) {
1137 IWineD3DSurface_Release(object->surfaces[l][i]);
1139 for (k = 0; k < i; k++) {
1140 for (l = 0; l < 6; l++) {
1141 IWineD3DSurface_Release(object->surfaces[l][k]);
1145 FIXME("(%p) Failed to create surface\n",object);
1146 HeapFree(GetProcessHeap(),0,object);
1147 *ppCubeTexture = NULL;
1150 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1151 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1153 tmpW = max(1, tmpW >> 1);
1155 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1157 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1158 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1162 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1164 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1165 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1166 const IWineD3DQueryVtbl *vtable;
1168 /* Just a check to see if we support this type of query */
1170 case WINED3DQUERYTYPE_OCCLUSION:
1171 TRACE("(%p) occlusion query\n", This);
1172 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1175 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1177 vtable = &IWineD3DOcclusionQuery_Vtbl;
1180 case WINED3DQUERYTYPE_EVENT:
1181 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1182 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1183 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1185 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1187 vtable = &IWineD3DEventQuery_Vtbl;
1191 case WINED3DQUERYTYPE_VCACHE:
1192 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1193 case WINED3DQUERYTYPE_VERTEXSTATS:
1194 case WINED3DQUERYTYPE_TIMESTAMP:
1195 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1196 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1197 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1198 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1199 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1200 case WINED3DQUERYTYPE_PIXELTIMINGS:
1201 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1202 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1204 /* Use the base Query vtable until we have a special one for each query */
1205 vtable = &IWineD3DQuery_Vtbl;
1206 FIXME("(%p) Unhandled query type %d\n", This, Type);
1208 if(NULL == ppQuery || hr != WINED3D_OK) {
1212 D3DCREATEOBJECTINSTANCE(object, Query)
1213 object->lpVtbl = vtable;
1214 object->type = Type;
1215 object->state = QUERY_CREATED;
1216 /* allocated the 'extended' data based on the type of query requested */
1218 case WINED3DQUERYTYPE_OCCLUSION:
1219 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1220 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1222 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1223 TRACE("(%p) Allocating data for an occlusion query\n", This);
1224 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1227 case WINED3DQUERYTYPE_EVENT:
1228 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1229 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1231 if(GL_SUPPORT(APPLE_FENCE)) {
1232 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1233 checkGLcall("glGenFencesAPPLE");
1234 } else if(GL_SUPPORT(NV_FENCE)) {
1235 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesNV");
1240 case WINED3DQUERYTYPE_VCACHE:
1241 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1242 case WINED3DQUERYTYPE_VERTEXSTATS:
1243 case WINED3DQUERYTYPE_TIMESTAMP:
1244 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1245 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1246 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1247 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1248 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1249 case WINED3DQUERYTYPE_PIXELTIMINGS:
1250 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1251 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1253 object->extendedData = 0;
1254 FIXME("(%p) Unhandled query type %d\n",This , Type);
1256 TRACE("(%p) : Created Query %p\n", This, object);
1260 /*****************************************************************************
1261 * IWineD3DDeviceImpl_SetupFullscreenWindow
1263 * Helper function that modifies a HWND's Style and ExStyle for proper
1267 * iface: Pointer to the IWineD3DDevice interface
1268 * window: Window to setup
1270 *****************************************************************************/
1271 static LONG fullscreen_style(LONG orig_style) {
1272 LONG style = orig_style;
1273 style &= ~WS_CAPTION;
1274 style &= ~WS_THICKFRAME;
1276 /* Make sure the window is managed, otherwise we won't get keyboard input */
1277 style |= WS_POPUP | WS_SYSMENU;
1282 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1283 LONG exStyle = orig_exStyle;
1285 /* Filter out window decorations */
1286 exStyle &= ~WS_EX_WINDOWEDGE;
1287 exStyle &= ~WS_EX_CLIENTEDGE;
1292 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1295 LONG style, exStyle;
1296 /* Don't do anything if an original style is stored.
1297 * That shouldn't happen
1299 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1300 if (This->style || This->exStyle) {
1301 ERR("(%p): Want to change the window parameters of HWND %p, but "
1302 "another style is stored for restoration afterwards\n", This, window);
1305 /* Get the parameters and save them */
1306 style = GetWindowLongW(window, GWL_STYLE);
1307 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1308 This->style = style;
1309 This->exStyle = exStyle;
1311 style = fullscreen_style(style);
1312 exStyle = fullscreen_exStyle(exStyle);
1314 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1315 This->style, This->exStyle, style, exStyle);
1317 SetWindowLongW(window, GWL_STYLE, style);
1318 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1320 /* Inform the window about the update. */
1321 SetWindowPos(window, HWND_TOP, 0, 0,
1322 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1325 /*****************************************************************************
1326 * IWineD3DDeviceImpl_RestoreWindow
1328 * Helper function that restores a windows' properties when taking it out
1329 * of fullscreen mode
1332 * iface: Pointer to the IWineD3DDevice interface
1333 * window: Window to setup
1335 *****************************************************************************/
1336 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1338 LONG style, exStyle;
1340 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1341 * switch, do nothing
1343 if (!This->style && !This->exStyle) return;
1345 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1346 This, window, This->style, This->exStyle);
1348 style = GetWindowLongW(window, GWL_STYLE);
1349 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1351 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1352 * Some applications change it before calling Reset() when switching between windowed and
1353 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1355 if(style == fullscreen_style(This->style) &&
1356 exStyle == fullscreen_style(This->exStyle)) {
1357 SetWindowLongW(window, GWL_STYLE, This->style);
1358 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1361 /* Delete the old values */
1365 /* Inform the window about the update */
1366 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1367 0, 0, 0, 0, /* Pos, Size, ignored */
1368 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1371 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1372 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1374 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1375 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1376 WINED3DSURFTYPE surface_type) {
1377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1380 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1381 HRESULT hr = WINED3D_OK;
1382 IUnknown *bufferParent;
1383 BOOL displaymode_set = FALSE;
1384 WINED3DDISPLAYMODE Mode;
1385 const StaticPixelFormatDesc *formatDesc;
1387 TRACE("(%p) : Created Additional Swap Chain\n", This);
1389 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1390 * does a device hold a reference to a swap chain giving them a lifetime of the device
1391 * or does the swap chain notify the device of its destruction.
1392 *******************************/
1394 /* Check the params */
1395 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1396 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1397 return WINED3DERR_INVALIDCALL;
1398 } else if (pPresentationParameters->BackBufferCount > 1) {
1399 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");
1402 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1403 switch(surface_type) {
1405 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1407 case SURFACE_OPENGL:
1408 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1410 case SURFACE_UNKNOWN:
1411 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1412 return WINED3DERR_INVALIDCALL;
1415 /*********************
1416 * Lookup the window Handle and the relating X window handle
1417 ********************/
1419 /* Setup hwnd we are using, plus which display this equates to */
1420 object->win_handle = pPresentationParameters->hDeviceWindow;
1421 if (!object->win_handle) {
1422 object->win_handle = This->createParms.hFocusWindow;
1424 if(!pPresentationParameters->Windowed && object->win_handle) {
1425 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1426 pPresentationParameters->BackBufferWidth,
1427 pPresentationParameters->BackBufferHeight);
1430 hDc = GetDC(object->win_handle);
1431 TRACE("Using hDc %p\n", hDc);
1434 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1435 return WINED3DERR_NOTAVAILABLE;
1438 /* Get info on the current display setup */
1439 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1440 object->orig_width = Mode.Width;
1441 object->orig_height = Mode.Height;
1442 object->orig_fmt = Mode.Format;
1443 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1445 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1446 * then the corresponding dimension of the client area of the hDeviceWindow
1447 * (or the focus window, if hDeviceWindow is NULL) is taken.
1448 **********************/
1450 if (pPresentationParameters->Windowed &&
1451 ((pPresentationParameters->BackBufferWidth == 0) ||
1452 (pPresentationParameters->BackBufferHeight == 0) ||
1453 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1456 GetClientRect(object->win_handle, &Rect);
1458 if (pPresentationParameters->BackBufferWidth == 0) {
1459 pPresentationParameters->BackBufferWidth = Rect.right;
1460 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1462 if (pPresentationParameters->BackBufferHeight == 0) {
1463 pPresentationParameters->BackBufferHeight = Rect.bottom;
1464 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1466 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1467 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1468 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1472 /* Put the correct figures in the presentation parameters */
1473 TRACE("Copying across presentation parameters\n");
1474 object->presentParms = *pPresentationParameters;
1476 TRACE("calling rendertarget CB\n");
1477 hr = D3DCB_CreateRenderTarget(This->parent,
1479 object->presentParms.BackBufferWidth,
1480 object->presentParms.BackBufferHeight,
1481 object->presentParms.BackBufferFormat,
1482 object->presentParms.MultiSampleType,
1483 object->presentParms.MultiSampleQuality,
1484 TRUE /* Lockable */,
1485 &object->frontBuffer,
1486 NULL /* pShared (always null)*/);
1487 if (object->frontBuffer != NULL) {
1488 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1489 if(surface_type == SURFACE_OPENGL) {
1490 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1493 ERR("Failed to create the front buffer\n");
1497 /*********************
1498 * Windowed / Fullscreen
1499 *******************/
1502 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1503 * so we should really check to see if there is a fullscreen swapchain already
1504 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1505 **************************************/
1507 if (!pPresentationParameters->Windowed) {
1508 WINED3DDISPLAYMODE mode;
1511 /* Change the display settings */
1512 mode.Width = pPresentationParameters->BackBufferWidth;
1513 mode.Height = pPresentationParameters->BackBufferHeight;
1514 mode.Format = pPresentationParameters->BackBufferFormat;
1515 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1517 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1518 displaymode_set = TRUE;
1522 * Create an opengl context for the display visual
1523 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1524 * use different properties after that point in time. FIXME: How to handle when requested format
1525 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1526 * it chooses is identical to the one already being used!
1527 **********************************/
1528 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1530 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1531 if(!object->context)
1532 return E_OUTOFMEMORY;
1533 object->num_contexts = 1;
1535 if(surface_type == SURFACE_OPENGL) {
1536 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1537 if (!object->context[0]) {
1538 ERR("Failed to create a new context\n");
1539 hr = WINED3DERR_NOTAVAILABLE;
1542 TRACE("Context created (HWND=%p, glContext=%p)\n",
1543 object->win_handle, object->context[0]->glCtx);
1547 /*********************
1548 * Create the back, front and stencil buffers
1549 *******************/
1550 if(object->presentParms.BackBufferCount > 0) {
1553 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1554 if(!object->backBuffer) {
1555 ERR("Out of memory\n");
1560 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1561 TRACE("calling rendertarget CB\n");
1562 hr = D3DCB_CreateRenderTarget(This->parent,
1564 object->presentParms.BackBufferWidth,
1565 object->presentParms.BackBufferHeight,
1566 object->presentParms.BackBufferFormat,
1567 object->presentParms.MultiSampleType,
1568 object->presentParms.MultiSampleQuality,
1569 TRUE /* Lockable */,
1570 &object->backBuffer[i],
1571 NULL /* pShared (always null)*/);
1572 if(hr == WINED3D_OK && object->backBuffer[i]) {
1573 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1575 ERR("Cannot create new back buffer\n");
1578 if(surface_type == SURFACE_OPENGL) {
1580 glDrawBuffer(GL_BACK);
1581 checkGLcall("glDrawBuffer(GL_BACK)");
1586 object->backBuffer = NULL;
1588 /* Single buffering - draw to front buffer */
1589 if(surface_type == SURFACE_OPENGL) {
1591 glDrawBuffer(GL_FRONT);
1592 checkGLcall("glDrawBuffer(GL_FRONT)");
1597 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1598 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1599 TRACE("Creating depth stencil buffer\n");
1600 if (This->auto_depth_stencil_buffer == NULL ) {
1601 hr = D3DCB_CreateDepthStencil(This->parent,
1603 object->presentParms.BackBufferWidth,
1604 object->presentParms.BackBufferHeight,
1605 object->presentParms.AutoDepthStencilFormat,
1606 object->presentParms.MultiSampleType,
1607 object->presentParms.MultiSampleQuality,
1608 FALSE /* FIXME: Discard */,
1609 &This->auto_depth_stencil_buffer,
1610 NULL /* pShared (always null)*/ );
1611 if (This->auto_depth_stencil_buffer != NULL)
1612 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1615 /** TODO: A check on width, height and multisample types
1616 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1617 ****************************/
1618 object->wantsDepthStencilBuffer = TRUE;
1620 object->wantsDepthStencilBuffer = FALSE;
1623 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1625 TRACE("Created swapchain %p\n", object);
1626 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1630 if (displaymode_set) {
1634 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1637 /* Change the display settings */
1638 memset(&devmode, 0, sizeof(devmode));
1639 devmode.dmSize = sizeof(devmode);
1640 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1641 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1642 devmode.dmPelsWidth = object->orig_width;
1643 devmode.dmPelsHeight = object->orig_height;
1644 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1647 if (object->backBuffer) {
1649 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1650 if(object->backBuffer[i]) {
1651 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1652 IUnknown_Release(bufferParent); /* once for the get parent */
1653 if (IUnknown_Release(bufferParent) > 0) {
1654 FIXME("(%p) Something's still holding the back buffer\n",This);
1658 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1659 object->backBuffer = NULL;
1661 if(object->context[0])
1662 DestroyContext(This, object->context[0]);
1663 if(object->frontBuffer) {
1664 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1665 IUnknown_Release(bufferParent); /* once for the get parent */
1666 if (IUnknown_Release(bufferParent) > 0) {
1667 FIXME("(%p) Something's still holding the front buffer\n",This);
1670 HeapFree(GetProcessHeap(), 0, object);
1674 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1675 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1677 TRACE("(%p)\n", This);
1679 return This->NumberOfSwapChains;
1682 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1684 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1686 if(iSwapChain < This->NumberOfSwapChains) {
1687 *pSwapChain = This->swapchains[iSwapChain];
1688 IWineD3DSwapChain_AddRef(*pSwapChain);
1689 TRACE("(%p) returning %p\n", This, *pSwapChain);
1692 TRACE("Swapchain out of range\n");
1694 return WINED3DERR_INVALIDCALL;
1699 * Vertex Declaration
1701 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1702 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1704 IWineD3DVertexDeclarationImpl *object = NULL;
1705 HRESULT hr = WINED3D_OK;
1707 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1708 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1710 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1712 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1714 *ppVertexDeclaration = NULL;
1715 HeapFree(GetProcessHeap(), 0, object);
1721 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1722 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1724 unsigned int idx, idx2;
1725 unsigned int offset;
1726 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1727 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1728 BOOL has_blend_idx = has_blend &&
1729 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1730 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1731 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1732 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1733 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1734 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1735 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1737 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1738 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1740 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1741 WINED3DVERTEXELEMENT *elements = NULL;
1744 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1745 if (has_blend_idx) num_blends--;
1747 /* Compute declaration size */
1748 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1749 has_psize + has_diffuse + has_specular + num_textures + 1;
1751 /* convert the declaration */
1752 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1756 elements[size-1] = end_element;
1759 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1760 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1761 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1765 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1767 elements[idx].UsageIndex = 0;
1770 if (has_blend && (num_blends > 0)) {
1771 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1772 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1774 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1775 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1776 elements[idx].UsageIndex = 0;
1779 if (has_blend_idx) {
1780 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1781 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1782 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1783 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1784 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1786 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1787 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1788 elements[idx].UsageIndex = 0;
1792 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1793 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1794 elements[idx].UsageIndex = 0;
1798 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1799 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1800 elements[idx].UsageIndex = 0;
1804 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1805 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1806 elements[idx].UsageIndex = 0;
1810 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1811 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1812 elements[idx].UsageIndex = 1;
1815 for (idx2 = 0; idx2 < num_textures; idx2++) {
1816 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1817 switch (numcoords) {
1818 case WINED3DFVF_TEXTUREFORMAT1:
1819 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1821 case WINED3DFVF_TEXTUREFORMAT2:
1822 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1824 case WINED3DFVF_TEXTUREFORMAT3:
1825 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1827 case WINED3DFVF_TEXTUREFORMAT4:
1828 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1831 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1832 elements[idx].UsageIndex = idx2;
1836 /* Now compute offsets, and initialize the rest of the fields */
1837 for (idx = 0, offset = 0; idx < size-1; idx++) {
1838 elements[idx].Stream = 0;
1839 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1840 elements[idx].Offset = offset;
1841 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1844 *ppVertexElements = elements;
1848 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1849 WINED3DVERTEXELEMENT* elements = NULL;
1850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1854 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1855 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1857 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1858 HeapFree(GetProcessHeap(), 0, elements);
1859 if (hr != S_OK) return hr;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1866 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1867 HRESULT hr = WINED3D_OK;
1868 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1869 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1871 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1873 if (vertex_declaration) {
1874 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1877 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1879 if (WINED3D_OK != hr) {
1880 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1881 IWineD3DVertexShader_Release(*ppVertexShader);
1882 return WINED3DERR_INVALIDCALL;
1884 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1889 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1891 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1892 HRESULT hr = WINED3D_OK;
1894 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1895 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1896 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1897 if (WINED3D_OK == hr) {
1898 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1899 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1901 WARN("(%p) : Failed to create pixel shader\n", This);
1907 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1909 IWineD3DPaletteImpl *object;
1911 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1913 /* Create the new object */
1914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1916 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1917 return E_OUTOFMEMORY;
1920 object->lpVtbl = &IWineD3DPalette_Vtbl;
1922 object->Flags = Flags;
1923 object->parent = Parent;
1924 object->wineD3DDevice = This;
1925 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1927 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1930 HeapFree( GetProcessHeap(), 0, object);
1931 return E_OUTOFMEMORY;
1934 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1936 IWineD3DPalette_Release((IWineD3DPalette *) object);
1940 *Palette = (IWineD3DPalette *) object;
1945 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1949 HDC dcb = NULL, dcs = NULL;
1950 WINEDDCOLORKEY colorkey;
1952 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1955 GetObjectA(hbm, sizeof(BITMAP), &bm);
1956 dcb = CreateCompatibleDC(NULL);
1958 SelectObject(dcb, hbm);
1962 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1963 * couldn't be loaded
1965 memset(&bm, 0, sizeof(bm));
1970 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1971 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1972 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1974 ERR("Wine logo requested, but failed to create surface\n");
1979 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1980 if(FAILED(hr)) goto out;
1981 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1982 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1984 colorkey.dwColorSpaceLowValue = 0;
1985 colorkey.dwColorSpaceHighValue = 0;
1986 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1988 /* Fill the surface with a white color to show that wined3d is there */
1989 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2002 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2004 /* Under DirectX you can have texture stage operations even if no texture is
2005 bound, whereas opengl will only do texture operations when a valid texture is
2006 bound. We emulate this by creating dummy textures and binding them to each
2007 texture stage, but disable all stages by default. Hence if a stage is enabled
2008 then the default texture will kick in until replaced by a SetTexture call */
2011 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2012 /* The dummy texture does not have client storage backing */
2013 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2014 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2016 for (i = 0; i < GL_LIMITS(textures); i++) {
2017 GLubyte white = 255;
2019 /* Make appropriate texture active */
2020 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2021 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2022 checkGLcall("glActiveTextureARB");
2024 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2027 /* Generate an opengl texture name */
2028 glGenTextures(1, &This->dummyTextureName[i]);
2029 checkGLcall("glGenTextures");
2030 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2032 /* Generate a dummy 2d texture (not using 1d because they cause many
2033 * DRI drivers fall back to sw) */
2034 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2035 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2036 checkGLcall("glBindTexture");
2038 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2039 checkGLcall("glTexImage2D");
2041 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2042 /* Reenable because if supported it is enabled by default */
2043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2050 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2052 IWineD3DSwapChainImpl *swapchain = NULL;
2057 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2058 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2059 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2061 /* TODO: Test if OpenGL is compiled in and loaded */
2063 TRACE("(%p) : Creating stateblock\n", This);
2064 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2065 hr = IWineD3DDevice_CreateStateBlock(iface,
2067 (IWineD3DStateBlock **)&This->stateBlock,
2069 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2070 WARN("Failed to create stateblock\n");
2073 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2074 This->updateStateBlock = This->stateBlock;
2075 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2077 hr = allocate_shader_constants(This->updateStateBlock);
2078 if (WINED3D_OK != hr) {
2082 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2083 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2085 This->NumberOfPalettes = 1;
2086 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2087 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2088 ERR("Out of memory!\n");
2091 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2092 if(!This->palettes[0]) {
2093 ERR("Out of memory!\n");
2096 for (i = 0; i < 256; ++i) {
2097 This->palettes[0][i].peRed = 0xFF;
2098 This->palettes[0][i].peGreen = 0xFF;
2099 This->palettes[0][i].peBlue = 0xFF;
2100 This->palettes[0][i].peFlags = 0xFF;
2102 This->currentPalette = 0;
2104 /* Initialize the texture unit mapping to a 1:1 mapping */
2105 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2106 if (state < GL_LIMITS(fragment_samplers)) {
2107 This->texUnitMap[state] = state;
2108 This->rev_tex_unit_map[state] = state;
2110 This->texUnitMap[state] = -1;
2111 This->rev_tex_unit_map[state] = -1;
2115 /* Setup the implicit swapchain */
2116 TRACE("Creating implicit swapchain\n");
2117 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2118 if (FAILED(hr) || !swapchain) {
2119 WARN("Failed to create implicit swapchain\n");
2123 This->NumberOfSwapChains = 1;
2124 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2125 if(!This->swapchains) {
2126 ERR("Out of memory!\n");
2129 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2131 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2132 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2133 This->render_targets[0] = swapchain->backBuffer[0];
2134 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2137 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2138 This->render_targets[0] = swapchain->frontBuffer;
2139 This->lastActiveRenderTarget = swapchain->frontBuffer;
2141 IWineD3DSurface_AddRef(This->render_targets[0]);
2142 This->activeContext = swapchain->context[0];
2143 This->lastThread = GetCurrentThreadId();
2145 /* Depth Stencil support */
2146 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2147 if (NULL != This->stencilBufferTarget) {
2148 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2151 hr = This->shader_backend->shader_alloc_private(iface);
2153 TRACE("Shader private data couldn't be allocated\n");
2156 hr = This->frag_pipe->alloc_private(iface);
2158 TRACE("Fragment pipeline private data couldn't be allocated\n");
2161 hr = This->blitter->alloc_private(iface);
2163 TRACE("Blitter private data couldn't be allocated\n");
2167 /* Set up some starting GL setup */
2169 /* Setup all the devices defaults */
2170 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2171 create_dummy_textures(This);
2175 { /* Set a default viewport */
2179 vp.Width = pPresentationParameters->BackBufferWidth;
2180 vp.Height = pPresentationParameters->BackBufferHeight;
2183 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2186 /* Initialize the current view state */
2187 This->view_ident = 1;
2188 This->contexts[0]->last_was_rhw = 0;
2189 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2190 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2192 switch(wined3d_settings.offscreen_rendering_mode) {
2195 This->offscreenBuffer = GL_BACK;
2198 case ORM_BACKBUFFER:
2200 if(This->activeContext->aux_buffers > 0) {
2201 TRACE("Using auxilliary buffer for offscreen rendering\n");
2202 This->offscreenBuffer = GL_AUX0;
2204 TRACE("Using back buffer for offscreen rendering\n");
2205 This->offscreenBuffer = GL_BACK;
2210 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2213 /* Clear the screen */
2214 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2215 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2218 This->d3d_initialized = TRUE;
2220 if(wined3d_settings.logo) {
2221 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2223 This->highest_dirty_ps_const = 0;
2224 This->highest_dirty_vs_const = 0;
2228 HeapFree(GetProcessHeap(), 0, This->render_targets);
2229 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2230 HeapFree(GetProcessHeap(), 0, This->swapchains);
2231 This->NumberOfSwapChains = 0;
2232 if(This->palettes) {
2233 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2234 HeapFree(GetProcessHeap(), 0, This->palettes);
2236 This->NumberOfPalettes = 0;
2238 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2240 if(This->stateBlock) {
2241 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2242 This->stateBlock = NULL;
2244 if (This->blit_priv) {
2245 This->blitter->free_private(iface);
2247 if (This->fragment_priv) {
2248 This->frag_pipe->free_private(iface);
2250 if (This->shader_priv) {
2251 This->shader_backend->shader_free_private(iface);
2256 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2258 IWineD3DSwapChainImpl *swapchain = NULL;
2261 /* Setup the implicit swapchain */
2262 TRACE("Creating implicit swapchain\n");
2263 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2264 if (FAILED(hr) || !swapchain) {
2265 WARN("Failed to create implicit swapchain\n");
2269 This->NumberOfSwapChains = 1;
2270 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2271 if(!This->swapchains) {
2272 ERR("Out of memory!\n");
2275 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2279 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2283 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2287 TRACE("(%p)\n", This);
2289 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2291 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2292 * it was created. Thus make sure a context is active for the glDelete* calls
2294 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2296 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2298 TRACE("Deleting high order patches\n");
2299 for(i = 0; i < PATCHMAP_SIZE; i++) {
2300 struct list *e1, *e2;
2301 struct WineD3DRectPatch *patch;
2302 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2303 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2304 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2308 /* Delete the palette conversion shader if it is around */
2309 if(This->paletteConversionShader) {
2311 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2313 This->paletteConversionShader = 0;
2316 /* Delete the pbuffer context if there is any */
2317 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2319 /* Delete the mouse cursor texture */
2320 if(This->cursorTexture) {
2322 glDeleteTextures(1, &This->cursorTexture);
2324 This->cursorTexture = 0;
2327 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2328 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2330 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2331 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2334 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2335 * private data, it might contain opengl pointers
2337 if(This->depth_blt_texture) {
2338 glDeleteTextures(1, &This->depth_blt_texture);
2339 This->depth_blt_texture = 0;
2341 if (This->depth_blt_rb) {
2342 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2343 This->depth_blt_rb = 0;
2344 This->depth_blt_rb_w = 0;
2345 This->depth_blt_rb_h = 0;
2348 /* Release the update stateblock */
2349 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2350 if(This->updateStateBlock != This->stateBlock)
2351 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2353 This->updateStateBlock = NULL;
2355 { /* because were not doing proper internal refcounts releasing the primary state block
2356 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2357 to set this->stateBlock = NULL; first */
2358 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2359 This->stateBlock = NULL;
2361 /* Release the stateblock */
2362 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2363 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2367 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2368 This->blitter->free_private(iface);
2369 This->frag_pipe->free_private(iface);
2370 This->shader_backend->shader_free_private(iface);
2372 /* Release the buffers (with sanity checks)*/
2373 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2374 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2375 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2376 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2378 This->stencilBufferTarget = NULL;
2380 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2381 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2382 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2384 TRACE("Setting rendertarget to NULL\n");
2385 This->render_targets[0] = NULL;
2387 if (This->auto_depth_stencil_buffer) {
2388 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2389 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2391 This->auto_depth_stencil_buffer = NULL;
2394 for(i=0; i < This->NumberOfSwapChains; i++) {
2395 TRACE("Releasing the implicit swapchain %d\n", i);
2396 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2397 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2401 HeapFree(GetProcessHeap(), 0, This->swapchains);
2402 This->swapchains = NULL;
2403 This->NumberOfSwapChains = 0;
2405 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2406 HeapFree(GetProcessHeap(), 0, This->palettes);
2407 This->palettes = NULL;
2408 This->NumberOfPalettes = 0;
2410 HeapFree(GetProcessHeap(), 0, This->render_targets);
2411 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2412 This->render_targets = NULL;
2413 This->draw_buffers = NULL;
2415 This->d3d_initialized = FALSE;
2419 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2423 for(i=0; i < This->NumberOfSwapChains; i++) {
2424 TRACE("Releasing the implicit swapchain %d\n", i);
2425 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2426 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2430 HeapFree(GetProcessHeap(), 0, This->swapchains);
2431 This->swapchains = NULL;
2432 This->NumberOfSwapChains = 0;
2436 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2437 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2438 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2440 * There is no way to deactivate thread safety once it is enabled.
2442 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2445 /*For now just store the flag(needed in case of ddraw) */
2446 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2451 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2458 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2460 /* Resize the screen even without a window:
2461 * The app could have unset it with SetCooperativeLevel, but not called
2462 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2463 * but we don't have any hwnd
2466 memset(&devmode, 0, sizeof(devmode));
2467 devmode.dmSize = sizeof(devmode);
2468 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2469 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2470 devmode.dmPelsWidth = pMode->Width;
2471 devmode.dmPelsHeight = pMode->Height;
2473 devmode.dmDisplayFrequency = pMode->RefreshRate;
2474 if (pMode->RefreshRate != 0) {
2475 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2478 /* Only change the mode if necessary */
2479 if( (This->ddraw_width == pMode->Width) &&
2480 (This->ddraw_height == pMode->Height) &&
2481 (This->ddraw_format == pMode->Format) &&
2482 (pMode->RefreshRate == 0) ) {
2486 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2487 if (ret != DISP_CHANGE_SUCCESSFUL) {
2488 if(devmode.dmDisplayFrequency != 0) {
2489 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2490 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2491 devmode.dmDisplayFrequency = 0;
2492 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2494 if(ret != DISP_CHANGE_SUCCESSFUL) {
2495 return WINED3DERR_NOTAVAILABLE;
2499 /* Store the new values */
2500 This->ddraw_width = pMode->Width;
2501 This->ddraw_height = pMode->Height;
2502 This->ddraw_format = pMode->Format;
2504 /* And finally clip mouse to our screen */
2505 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2506 ClipCursor(&clip_rc);
2511 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 *ppD3D= This->wineD3D;
2514 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2515 IWineD3D_AddRef(*ppD3D);
2519 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2522 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2523 (This->adapter->TextureRam/(1024*1024)),
2524 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2525 /* return simulated texture memory left */
2526 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2534 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 /* Update the current state block */
2538 This->updateStateBlock->changed.fvf = TRUE;
2540 if(This->updateStateBlock->fvf == fvf) {
2541 TRACE("Application is setting the old fvf over, nothing to do\n");
2545 This->updateStateBlock->fvf = fvf;
2546 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2552 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2555 *pfvf = This->stateBlock->fvf;
2560 * Get / Set Stream Source
2562 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 IWineD3DVertexBuffer *oldSrc;
2566 if (StreamNumber >= MAX_STREAMS) {
2567 WARN("Stream out of range %d\n", StreamNumber);
2568 return WINED3DERR_INVALIDCALL;
2569 } else if(OffsetInBytes & 0x3) {
2570 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2571 return WINED3DERR_INVALIDCALL;
2574 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2575 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2577 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2579 if(oldSrc == pStreamData &&
2580 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2581 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2582 TRACE("Application is setting the old values over, nothing to do\n");
2586 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2588 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2589 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2592 /* Handle recording of state blocks */
2593 if (This->isRecordingState) {
2594 TRACE("Recording... not performing anything\n");
2595 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2596 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2600 /* Need to do a getParent and pass the references up */
2601 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2602 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2603 so for now, just count internally */
2604 if (pStreamData != NULL) {
2605 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2606 InterlockedIncrement(&vbImpl->bindCount);
2607 IWineD3DVertexBuffer_AddRef(pStreamData);
2609 if (oldSrc != NULL) {
2610 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2611 IWineD3DVertexBuffer_Release(oldSrc);
2614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2619 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2622 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2623 This->stateBlock->streamSource[StreamNumber],
2624 This->stateBlock->streamOffset[StreamNumber],
2625 This->stateBlock->streamStride[StreamNumber]);
2627 if (StreamNumber >= MAX_STREAMS) {
2628 WARN("Stream out of range %d\n", StreamNumber);
2629 return WINED3DERR_INVALIDCALL;
2631 *pStream = This->stateBlock->streamSource[StreamNumber];
2632 *pStride = This->stateBlock->streamStride[StreamNumber];
2634 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2637 if (*pStream != NULL) {
2638 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2643 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2646 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2648 /* Verify input at least in d3d9 this is invalid*/
2649 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2650 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2651 return WINED3DERR_INVALIDCALL;
2653 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2654 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2658 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2662 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2663 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2665 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2666 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2668 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2669 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2670 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2676 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2679 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2680 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2682 TRACE("(%p) : returning %d\n", This, *Divider);
2688 * Get / Set & Multiply Transform
2690 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 /* Most of this routine, comments included copied from ddraw tree initially: */
2694 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2696 /* Handle recording of state blocks */
2697 if (This->isRecordingState) {
2698 TRACE("Recording... not performing anything\n");
2699 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2700 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2705 * If the new matrix is the same as the current one,
2706 * we cut off any further processing. this seems to be a reasonable
2707 * optimization because as was noticed, some apps (warcraft3 for example)
2708 * tend towards setting the same matrix repeatedly for some reason.
2710 * From here on we assume that the new matrix is different, wherever it matters.
2712 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2713 TRACE("The app is setting the same matrix over again\n");
2716 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2720 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2721 where ViewMat = Camera space, WorldMat = world space.
2723 In OpenGL, camera and world space is combined into GL_MODELVIEW
2724 matrix. The Projection matrix stay projection matrix.
2727 /* Capture the times we can just ignore the change for now */
2728 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2729 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2730 /* Handled by the state manager */
2733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2737 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2739 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2740 *pMatrix = This->stateBlock->transforms[State];
2744 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2745 WINED3DMATRIX *mat = NULL;
2748 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2749 * below means it will be recorded in a state block change, but it
2750 * works regardless where it is recorded.
2751 * If this is found to be wrong, change to StateBlock.
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2756 if (State < HIGHEST_TRANSFORMSTATE)
2758 mat = &This->updateStateBlock->transforms[State];
2760 FIXME("Unhandled transform state!!\n");
2763 multiply_matrix(&temp, mat, pMatrix);
2765 /* Apply change via set transform - will reapply to eg. lights this way */
2766 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2772 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2773 you can reference any indexes you want as long as that number max are enabled at any
2774 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2775 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2776 but when recording, just build a chain pretty much of commands to be replayed. */
2778 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2780 PLIGHTINFOEL *object = NULL;
2781 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2787 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2791 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2792 return WINED3DERR_INVALIDCALL;
2795 switch(pLight->Type) {
2796 case WINED3DLIGHT_POINT:
2797 case WINED3DLIGHT_SPOT:
2798 case WINED3DLIGHT_PARALLELPOINT:
2799 case WINED3DLIGHT_GLSPOT:
2800 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2803 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2804 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2805 return WINED3DERR_INVALIDCALL;
2809 case WINED3DLIGHT_DIRECTIONAL:
2810 /* Ignores attenuation */
2814 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2815 return WINED3DERR_INVALIDCALL;
2818 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2819 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2820 if(object->OriginalIndex == Index) break;
2825 TRACE("Adding new light\n");
2826 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2828 ERR("Out of memory error when allocating a light\n");
2829 return E_OUTOFMEMORY;
2831 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2832 object->glIndex = -1;
2833 object->OriginalIndex = Index;
2834 object->changed = TRUE;
2837 /* Initialize the object */
2838 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,
2839 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2840 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2841 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2842 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2843 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2844 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2846 /* Save away the information */
2847 object->OriginalParms = *pLight;
2849 switch (pLight->Type) {
2850 case WINED3DLIGHT_POINT:
2852 object->lightPosn[0] = pLight->Position.x;
2853 object->lightPosn[1] = pLight->Position.y;
2854 object->lightPosn[2] = pLight->Position.z;
2855 object->lightPosn[3] = 1.0f;
2856 object->cutoff = 180.0f;
2860 case WINED3DLIGHT_DIRECTIONAL:
2862 object->lightPosn[0] = -pLight->Direction.x;
2863 object->lightPosn[1] = -pLight->Direction.y;
2864 object->lightPosn[2] = -pLight->Direction.z;
2865 object->lightPosn[3] = 0.0;
2866 object->exponent = 0.0f;
2867 object->cutoff = 180.0f;
2870 case WINED3DLIGHT_SPOT:
2872 object->lightPosn[0] = pLight->Position.x;
2873 object->lightPosn[1] = pLight->Position.y;
2874 object->lightPosn[2] = pLight->Position.z;
2875 object->lightPosn[3] = 1.0;
2878 object->lightDirn[0] = pLight->Direction.x;
2879 object->lightDirn[1] = pLight->Direction.y;
2880 object->lightDirn[2] = pLight->Direction.z;
2881 object->lightDirn[3] = 1.0;
2884 * opengl-ish and d3d-ish spot lights use too different models for the
2885 * light "intensity" as a function of the angle towards the main light direction,
2886 * so we only can approximate very roughly.
2887 * however spot lights are rather rarely used in games (if ever used at all).
2888 * furthermore if still used, probably nobody pays attention to such details.
2890 if (pLight->Falloff == 0) {
2891 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2892 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2893 * will always be 1.0 for both of them, and we don't have to care for the
2894 * rest of the rather complex calculation
2896 object->exponent = 0;
2898 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2899 if (rho < 0.0001) rho = 0.0001f;
2900 object->exponent = -0.3/log(cos(rho/2));
2902 if (object->exponent > 128.0) {
2903 object->exponent = 128.0;
2905 object->cutoff = pLight->Phi*90/M_PI;
2911 FIXME("Unrecognized light type %d\n", pLight->Type);
2914 /* Update the live definitions if the light is currently assigned a glIndex */
2915 if (object->glIndex != -1 && !This->isRecordingState) {
2916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2921 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2922 PLIGHTINFOEL *lightInfo = NULL;
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2926 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2928 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2929 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2930 if(lightInfo->OriginalIndex == Index) break;
2934 if (lightInfo == NULL) {
2935 TRACE("Light information requested but light not defined\n");
2936 return WINED3DERR_INVALIDCALL;
2939 *pLight = lightInfo->OriginalParms;
2944 * Get / Set Light Enable
2945 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2948 PLIGHTINFOEL *lightInfo = NULL;
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2952 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2954 /* Tests show true = 128...not clear why */
2955 Enable = Enable? 128: 0;
2957 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2958 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2959 if(lightInfo->OriginalIndex == Index) break;
2962 TRACE("Found light: %p\n", lightInfo);
2964 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2965 if (lightInfo == NULL) {
2967 TRACE("Light enabled requested but light not defined, so defining one!\n");
2968 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2970 /* Search for it again! Should be fairly quick as near head of list */
2971 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2972 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2973 if(lightInfo->OriginalIndex == Index) break;
2976 if (lightInfo == NULL) {
2977 FIXME("Adding default lights has failed dismally\n");
2978 return WINED3DERR_INVALIDCALL;
2982 lightInfo->enabledChanged = TRUE;
2984 if(lightInfo->glIndex != -1) {
2985 if(!This->isRecordingState) {
2986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2989 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2990 lightInfo->glIndex = -1;
2992 TRACE("Light already disabled, nothing to do\n");
2994 lightInfo->enabled = FALSE;
2996 lightInfo->enabled = TRUE;
2997 if (lightInfo->glIndex != -1) {
2999 TRACE("Nothing to do as light was enabled\n");
3002 /* Find a free gl light */
3003 for(i = 0; i < This->maxConcurrentLights; i++) {
3004 if(This->stateBlock->activeLights[i] == NULL) {
3005 This->stateBlock->activeLights[i] = lightInfo;
3006 lightInfo->glIndex = i;
3010 if(lightInfo->glIndex == -1) {
3011 /* Our tests show that Windows returns D3D_OK in this situation, even with
3012 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3013 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3014 * as well for those lights.
3016 * TODO: Test how this affects rendering
3018 FIXME("Too many concurrently active lights\n");
3022 /* i == lightInfo->glIndex */
3023 if(!This->isRecordingState) {
3024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3034 PLIGHTINFOEL *lightInfo = NULL;
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3038 TRACE("(%p) : for idx(%d)\n", This, Index);
3040 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3041 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3042 if(lightInfo->OriginalIndex == Index) break;
3046 if (lightInfo == NULL) {
3047 TRACE("Light enabled state requested but light not defined\n");
3048 return WINED3DERR_INVALIDCALL;
3050 /* true is 128 according to SetLightEnable */
3051 *pEnable = lightInfo->enabled ? 128 : 0;
3056 * Get / Set Clip Planes
3058 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3062 /* Validate Index */
3063 if (Index >= GL_LIMITS(clipplanes)) {
3064 TRACE("Application has requested clipplane this device doesn't support\n");
3065 return WINED3DERR_INVALIDCALL;
3068 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3070 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3071 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3072 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3073 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3074 TRACE("Application is setting old values over, nothing to do\n");
3078 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3079 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3080 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3081 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3083 /* Handle recording of state blocks */
3084 if (This->isRecordingState) {
3085 TRACE("Recording... not performing anything\n");
3089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3094 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p) : for idx %d\n", This, Index);
3098 /* Validate Index */
3099 if (Index >= GL_LIMITS(clipplanes)) {
3100 TRACE("Application has requested clipplane this device doesn't support\n");
3101 return WINED3DERR_INVALIDCALL;
3104 pPlane[0] = This->stateBlock->clipplane[Index][0];
3105 pPlane[1] = This->stateBlock->clipplane[Index][1];
3106 pPlane[2] = This->stateBlock->clipplane[Index][2];
3107 pPlane[3] = This->stateBlock->clipplane[Index][3];
3112 * Get / Set Clip Plane Status
3113 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3115 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 FIXME("(%p) : stub\n", This);
3118 if (NULL == pClipStatus) {
3119 return WINED3DERR_INVALIDCALL;
3121 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3122 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 FIXME("(%p) : stub\n", This);
3129 if (NULL == pClipStatus) {
3130 return WINED3DERR_INVALIDCALL;
3132 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3133 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3138 * Get / Set Material
3140 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 This->updateStateBlock->changed.material = TRUE;
3144 This->updateStateBlock->material = *pMaterial;
3146 /* Handle recording of state blocks */
3147 if (This->isRecordingState) {
3148 TRACE("Recording... not performing anything\n");
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3156 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 *pMaterial = This->updateStateBlock->material;
3159 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3160 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3161 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3162 pMaterial->Ambient.b, pMaterial->Ambient.a);
3163 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3164 pMaterial->Specular.b, pMaterial->Specular.a);
3165 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3166 pMaterial->Emissive.b, pMaterial->Emissive.a);
3167 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3175 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 IWineD3DIndexBuffer *oldIdxs;
3179 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3180 oldIdxs = This->updateStateBlock->pIndexData;
3182 This->updateStateBlock->changed.indices = TRUE;
3183 This->updateStateBlock->pIndexData = pIndexData;
3185 /* Handle recording of state blocks */
3186 if (This->isRecordingState) {
3187 TRACE("Recording... not performing anything\n");
3188 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3189 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3193 if(oldIdxs != pIndexData) {
3194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3195 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3196 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3201 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3204 *ppIndexData = This->stateBlock->pIndexData;
3206 /* up ref count on ppindexdata */
3208 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3209 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3211 TRACE("(%p) No index data set\n", This);
3213 TRACE("Returning %p\n", *ppIndexData);
3218 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3219 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p)->(%d)\n", This, BaseIndex);
3223 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3224 TRACE("Application is setting the old value over, nothing to do\n");
3228 This->updateStateBlock->baseVertexIndex = BaseIndex;
3230 if (This->isRecordingState) {
3231 TRACE("Recording... not performing anything\n");
3234 /* The base vertex index affects the stream sources */
3235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3239 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3241 TRACE("(%p) : base_index %p\n", This, base_index);
3243 *base_index = This->stateBlock->baseVertexIndex;
3245 TRACE("Returning %u\n", *base_index);
3251 * Get / Set Viewports
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 TRACE("(%p)\n", This);
3257 This->updateStateBlock->changed.viewport = TRUE;
3258 This->updateStateBlock->viewport = *pViewport;
3260 /* Handle recording of state blocks */
3261 if (This->isRecordingState) {
3262 TRACE("Recording... not performing anything\n");
3266 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3267 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3274 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 TRACE("(%p)\n", This);
3277 *pViewport = This->stateBlock->viewport;
3282 * Get / Set Render States
3283 * TODO: Verify against dx9 definitions
3285 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3288 DWORD oldValue = This->stateBlock->renderState[State];
3290 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3292 This->updateStateBlock->changed.renderState[State] = TRUE;
3293 This->updateStateBlock->renderState[State] = Value;
3295 /* Handle recording of state blocks */
3296 if (This->isRecordingState) {
3297 TRACE("Recording... not performing anything\n");
3301 /* Compared here and not before the assignment to allow proper stateblock recording */
3302 if(Value == oldValue) {
3303 TRACE("Application is setting the old value over, nothing to do\n");
3305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3311 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3313 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3314 *pValue = This->stateBlock->renderState[State];
3319 * Get / Set Sampler States
3320 * TODO: Verify against dx9 definitions
3323 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3328 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3330 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3331 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3334 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3335 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3336 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3339 * SetSampler is designed to allow for more than the standard up to 8 textures
3340 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3341 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3343 * http://developer.nvidia.com/object/General_FAQ.html#t6
3345 * There are two new settings for GForce
3347 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3348 * and the texture one:
3349 * GL_MAX_TEXTURE_COORDS_ARB.
3350 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3353 oldValue = This->stateBlock->samplerState[Sampler][Type];
3354 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3355 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3357 /* Handle recording of state blocks */
3358 if (This->isRecordingState) {
3359 TRACE("Recording... not performing anything\n");
3363 if(oldValue == Value) {
3364 TRACE("Application is setting the old value over, nothing to do\n");
3368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3373 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3377 This, Sampler, debug_d3dsamplerstate(Type), Type);
3379 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3380 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3383 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3384 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3385 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3387 *Value = This->stateBlock->samplerState[Sampler][Type];
3388 TRACE("(%p) : Returning %#x\n", This, *Value);
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3396 This->updateStateBlock->changed.scissorRect = TRUE;
3397 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3398 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3401 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3403 if(This->isRecordingState) {
3404 TRACE("Recording... not performing anything\n");
3408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3413 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 *pRect = This->updateStateBlock->scissorRect;
3417 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3421 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3423 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3425 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3427 This->updateStateBlock->vertexDecl = pDecl;
3428 This->updateStateBlock->changed.vertexDecl = TRUE;
3430 if (This->isRecordingState) {
3431 TRACE("Recording... not performing anything\n");
3433 } else if(pDecl == oldDecl) {
3434 /* Checked after the assignment to allow proper stateblock recording */
3435 TRACE("Application is setting the old declaration over, nothing to do\n");
3439 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3443 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3446 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3448 *ppDecl = This->stateBlock->vertexDecl;
3449 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3453 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3455 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3457 This->updateStateBlock->vertexShader = pShader;
3458 This->updateStateBlock->changed.vertexShader = TRUE;
3460 if (This->isRecordingState) {
3461 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3462 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3463 TRACE("Recording... not performing anything\n");
3465 } else if(oldShader == pShader) {
3466 /* Checked here to allow proper stateblock recording */
3467 TRACE("App is setting the old shader over, nothing to do\n");
3471 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3472 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3473 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3480 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3483 if (NULL == ppShader) {
3484 return WINED3DERR_INVALIDCALL;
3486 *ppShader = This->stateBlock->vertexShader;
3487 if( NULL != *ppShader)
3488 IWineD3DVertexShader_AddRef(*ppShader);
3490 TRACE("(%p) : returning %p\n", This, *ppShader);
3494 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3495 IWineD3DDevice *iface,
3497 CONST BOOL *srcData,
3500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3501 int i, cnt = min(count, MAX_CONST_B - start);
3503 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3504 iface, srcData, start, count);
3506 if (srcData == NULL || cnt < 0)
3507 return WINED3DERR_INVALIDCALL;
3509 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3510 for (i = 0; i < cnt; i++)
3511 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3513 for (i = start; i < cnt + start; ++i) {
3514 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3522 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3523 IWineD3DDevice *iface,
3528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 int cnt = min(count, MAX_CONST_B - start);
3531 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3532 iface, dstData, start, count);
3534 if (dstData == NULL || cnt < 0)
3535 return WINED3DERR_INVALIDCALL;
3537 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3541 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3542 IWineD3DDevice *iface,
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 int i, cnt = min(count, MAX_CONST_I - start);
3550 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3551 iface, srcData, start, count);
3553 if (srcData == NULL || cnt < 0)
3554 return WINED3DERR_INVALIDCALL;
3556 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3557 for (i = 0; i < cnt; i++)
3558 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3559 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3561 for (i = start; i < cnt + start; ++i) {
3562 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3570 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3571 IWineD3DDevice *iface,
3576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 int cnt = min(count, MAX_CONST_I - start);
3579 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3580 iface, dstData, start, count);
3582 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3583 return WINED3DERR_INVALIDCALL;
3585 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3589 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3590 IWineD3DDevice *iface,
3592 CONST float *srcData,
3595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3598 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3599 iface, srcData, start, count);
3601 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3602 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3603 return WINED3DERR_INVALIDCALL;
3605 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3607 for (i = 0; i < count; i++)
3608 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3609 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3612 for (i = start; i < count + start; ++i) {
3613 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3614 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3615 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3616 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3617 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3619 ptr->idx[ptr->count++] = i;
3620 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3629 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3630 IWineD3DDevice *iface,
3632 CONST float *srcData,
3635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3638 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3639 iface, srcData, start, count);
3641 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3642 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3643 return WINED3DERR_INVALIDCALL;
3645 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3647 for (i = 0; i < count; i++)
3648 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3649 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3652 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3653 * context. On a context switch the old context will be fully dirtified
3655 memset(This->activeContext->vshader_const_dirty + start, 1,
3656 sizeof(*This->activeContext->vshader_const_dirty) * count);
3657 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3664 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3665 IWineD3DDevice *iface,
3670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3671 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3673 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3674 iface, dstData, start, count);
3676 if (dstData == NULL || cnt < 0)
3677 return WINED3DERR_INVALIDCALL;
3679 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3683 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3685 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3690 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3691 int i = This->rev_tex_unit_map[unit];
3692 int j = This->texUnitMap[stage];
3694 This->texUnitMap[stage] = unit;
3695 if (i != -1 && i != stage) {
3696 This->texUnitMap[i] = -1;
3699 This->rev_tex_unit_map[unit] = stage;
3700 if (j != -1 && j != unit) {
3701 This->rev_tex_unit_map[j] = -1;
3705 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3708 for (i = 0; i < MAX_TEXTURES; ++i) {
3709 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3710 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3711 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3712 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3713 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3714 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3715 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3716 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3718 if (color_op == WINED3DTOP_DISABLE) {
3719 /* Not used, and disable higher stages */
3720 while (i < MAX_TEXTURES) {
3721 This->fixed_function_usage_map[i] = FALSE;
3727 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3728 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3729 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3730 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3731 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3732 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3733 This->fixed_function_usage_map[i] = TRUE;
3735 This->fixed_function_usage_map[i] = FALSE;
3738 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3739 This->fixed_function_usage_map[i+1] = TRUE;
3744 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3747 device_update_fixed_function_usage_map(This);
3749 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3750 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3751 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3752 if (!This->fixed_function_usage_map[i]) continue;
3754 if (This->texUnitMap[i] != i) {
3755 device_map_stage(This, i, i);
3756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3757 markTextureStagesDirty(This, i);
3763 /* Now work out the mapping */
3765 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3766 if (!This->fixed_function_usage_map[i]) continue;
3768 if (This->texUnitMap[i] != tex) {
3769 device_map_stage(This, i, tex);
3770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3771 markTextureStagesDirty(This, i);
3778 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3779 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3782 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3783 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3784 device_map_stage(This, i, i);
3785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3786 if (i < MAX_TEXTURES) {
3787 markTextureStagesDirty(This, i);
3793 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3794 int current_mapping = This->rev_tex_unit_map[unit];
3796 if (current_mapping == -1) {
3797 /* Not currently used */
3801 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3802 /* Used by a fragment sampler */
3804 if (!pshader_sampler_tokens) {
3805 /* No pixel shader, check fixed function */
3806 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3809 /* Pixel shader, check the shader's sampler map */
3810 return !pshader_sampler_tokens[current_mapping];
3813 /* Used by a vertex sampler */
3814 return !vshader_sampler_tokens[current_mapping];
3817 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3818 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3819 DWORD *pshader_sampler_tokens = NULL;
3820 int start = GL_LIMITS(combined_samplers) - 1;
3824 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3826 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3827 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3828 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3831 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3832 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3833 if (vshader_sampler_tokens[i]) {
3834 if (This->texUnitMap[vsampler_idx] != -1) {
3835 /* Already mapped somewhere */
3839 while (start >= 0) {
3840 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3841 device_map_stage(This, vsampler_idx, start);
3842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3854 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3855 BOOL vs = use_vs(This);
3856 BOOL ps = use_ps(This);
3859 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3860 * that would be really messy and require shader recompilation
3861 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3862 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3865 device_map_psamplers(This);
3867 device_map_fixed_function_samplers(This);
3871 device_map_vsamplers(This, ps);
3875 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3878 This->updateStateBlock->pixelShader = pShader;
3879 This->updateStateBlock->changed.pixelShader = TRUE;
3881 /* Handle recording of state blocks */
3882 if (This->isRecordingState) {
3883 TRACE("Recording... not performing anything\n");
3886 if (This->isRecordingState) {
3887 TRACE("Recording... not performing anything\n");
3888 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3889 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3893 if(pShader == oldShader) {
3894 TRACE("App is setting the old pixel shader over, nothing to do\n");
3898 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3899 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3901 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3907 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3910 if (NULL == ppShader) {
3911 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3912 return WINED3DERR_INVALIDCALL;
3915 *ppShader = This->stateBlock->pixelShader;
3916 if (NULL != *ppShader) {
3917 IWineD3DPixelShader_AddRef(*ppShader);
3919 TRACE("(%p) : returning %p\n", This, *ppShader);
3923 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3924 IWineD3DDevice *iface,
3926 CONST BOOL *srcData,
3929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3930 int i, cnt = min(count, MAX_CONST_B - start);
3932 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3933 iface, srcData, start, count);
3935 if (srcData == NULL || cnt < 0)
3936 return WINED3DERR_INVALIDCALL;
3938 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3939 for (i = 0; i < cnt; i++)
3940 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3942 for (i = start; i < cnt + start; ++i) {
3943 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3946 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3951 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3952 IWineD3DDevice *iface,
3957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3958 int cnt = min(count, MAX_CONST_B - start);
3960 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3961 iface, dstData, start, count);
3963 if (dstData == NULL || cnt < 0)
3964 return WINED3DERR_INVALIDCALL;
3966 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3970 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3971 IWineD3DDevice *iface,
3976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3977 int i, cnt = min(count, MAX_CONST_I - start);
3979 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3980 iface, srcData, start, count);
3982 if (srcData == NULL || cnt < 0)
3983 return WINED3DERR_INVALIDCALL;
3985 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3986 for (i = 0; i < cnt; i++)
3987 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3988 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3990 for (i = start; i < cnt + start; ++i) {
3991 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3999 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4000 IWineD3DDevice *iface,
4005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4006 int cnt = min(count, MAX_CONST_I - start);
4008 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4009 iface, dstData, start, count);
4011 if (dstData == NULL || cnt < 0)
4012 return WINED3DERR_INVALIDCALL;
4014 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4018 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4019 IWineD3DDevice *iface,
4021 CONST float *srcData,
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4027 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4028 iface, srcData, start, count);
4030 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4031 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4032 return WINED3DERR_INVALIDCALL;
4034 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4036 for (i = 0; i < count; i++)
4037 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4038 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4041 for (i = start; i < count + start; ++i) {
4042 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4043 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4044 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4045 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4046 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4048 ptr->idx[ptr->count++] = i;
4049 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4058 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4059 IWineD3DDevice *iface,
4061 CONST float *srcData,
4064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4067 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4068 iface, srcData, start, count);
4070 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4071 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4072 return WINED3DERR_INVALIDCALL;
4074 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4076 for (i = 0; i < count; i++)
4077 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4078 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4081 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4082 * context. On a context switch the old context will be fully dirtified
4084 memset(This->activeContext->pshader_const_dirty + start, 1,
4085 sizeof(*This->activeContext->pshader_const_dirty) * count);
4086 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4093 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4094 IWineD3DDevice *iface,
4099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4100 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4102 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4103 iface, dstData, start, count);
4105 if (dstData == NULL || cnt < 0)
4106 return WINED3DERR_INVALIDCALL;
4108 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4112 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4114 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4115 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4117 DWORD DestFVF = dest->fvf;
4119 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4123 if (lpStrideData->u.s.normal.lpData) {
4124 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4127 if (lpStrideData->u.s.position.lpData == NULL) {
4128 ERR("Source has no position mask\n");
4129 return WINED3DERR_INVALIDCALL;
4132 /* We might access VBOs from this code, so hold the lock */
4135 if (dest->resource.allocatedMemory == NULL) {
4136 /* This may happen if we do direct locking into a vbo. Unlikely,
4137 * but theoretically possible(ddraw processvertices test)
4139 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4140 if(!dest->resource.allocatedMemory) {
4142 ERR("Out of memory\n");
4143 return E_OUTOFMEMORY;
4147 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4148 checkGLcall("glBindBufferARB");
4149 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4151 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4153 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4154 checkGLcall("glUnmapBufferARB");
4158 /* Get a pointer into the destination vbo(create one if none exists) and
4159 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4161 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4162 dest->Flags |= VBFLAG_CREATEVBO;
4163 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4167 unsigned char extrabytes = 0;
4168 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4169 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4170 * this may write 4 extra bytes beyond the area that should be written
4172 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4173 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4174 if(!dest_conv_addr) {
4175 ERR("Out of memory\n");
4176 /* Continue without storing converted vertices */
4178 dest_conv = dest_conv_addr;
4182 * a) WINED3DRS_CLIPPING is enabled
4183 * b) WINED3DVOP_CLIP is passed
4185 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4186 static BOOL warned = FALSE;
4188 * The clipping code is not quite correct. Some things need
4189 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4190 * so disable clipping for now.
4191 * (The graphics in Half-Life are broken, and my processvertices
4192 * test crashes with IDirect3DDevice3)
4198 FIXME("Clipping is broken and disabled for now\n");
4200 } else doClip = FALSE;
4201 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4203 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4206 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4207 WINED3DTS_PROJECTION,
4209 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4210 WINED3DTS_WORLDMATRIX(0),
4213 TRACE("View mat:\n");
4214 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);
4215 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);
4216 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);
4217 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);
4219 TRACE("Proj mat:\n");
4220 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);
4221 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);
4222 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);
4223 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);
4225 TRACE("World mat:\n");
4226 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);
4227 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);
4228 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);
4229 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);
4231 /* Get the viewport */
4232 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4233 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4234 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4236 multiply_matrix(&mat,&view_mat,&world_mat);
4237 multiply_matrix(&mat,&proj_mat,&mat);
4239 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4241 for (i = 0; i < dwCount; i+= 1) {
4242 unsigned int tex_index;
4244 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4245 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4246 /* The position first */
4248 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4250 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4252 /* Multiplication with world, view and projection matrix */
4253 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);
4254 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);
4255 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);
4256 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);
4258 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4260 /* WARNING: The following things are taken from d3d7 and were not yet checked
4261 * against d3d8 or d3d9!
4264 /* Clipping conditions: From msdn
4266 * A vertex is clipped if it does not match the following requirements
4270 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4272 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4273 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4278 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4279 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4282 /* "Normal" viewport transformation (not clipped)
4283 * 1) The values are divided by rhw
4284 * 2) The y axis is negative, so multiply it with -1
4285 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4286 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4287 * 4) Multiply x with Width/2 and add Width/2
4288 * 5) The same for the height
4289 * 6) Add the viewpoint X and Y to the 2D coordinates and
4290 * The minimum Z value to z
4291 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4293 * Well, basically it's simply a linear transformation into viewport
4305 z *= vp.MaxZ - vp.MinZ;
4307 x += vp.Width / 2 + vp.X;
4308 y += vp.Height / 2 + vp.Y;
4313 /* That vertex got clipped
4314 * Contrary to OpenGL it is not dropped completely, it just
4315 * undergoes a different calculation.
4317 TRACE("Vertex got clipped\n");
4324 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4325 * outside of the main vertex buffer memory. That needs some more
4330 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4333 ( (float *) dest_ptr)[0] = x;
4334 ( (float *) dest_ptr)[1] = y;
4335 ( (float *) dest_ptr)[2] = z;
4336 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4338 dest_ptr += 3 * sizeof(float);
4340 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4341 dest_ptr += sizeof(float);
4346 ( (float *) dest_conv)[0] = x * w;
4347 ( (float *) dest_conv)[1] = y * w;
4348 ( (float *) dest_conv)[2] = z * w;
4349 ( (float *) dest_conv)[3] = w;
4351 dest_conv += 3 * sizeof(float);
4353 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4354 dest_conv += sizeof(float);
4358 if (DestFVF & WINED3DFVF_PSIZE) {
4359 dest_ptr += sizeof(DWORD);
4360 if(dest_conv) dest_conv += sizeof(DWORD);
4362 if (DestFVF & WINED3DFVF_NORMAL) {
4364 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4365 /* AFAIK this should go into the lighting information */
4366 FIXME("Didn't expect the destination to have a normal\n");
4367 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4369 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4373 if (DestFVF & WINED3DFVF_DIFFUSE) {
4375 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4377 static BOOL warned = FALSE;
4380 ERR("No diffuse color in source, but destination has one\n");
4384 *( (DWORD *) dest_ptr) = 0xffffffff;
4385 dest_ptr += sizeof(DWORD);
4388 *( (DWORD *) dest_conv) = 0xffffffff;
4389 dest_conv += sizeof(DWORD);
4393 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4395 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4396 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4397 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4398 dest_conv += sizeof(DWORD);
4403 if (DestFVF & WINED3DFVF_SPECULAR) {
4404 /* What's the color value in the feedback buffer? */
4406 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4408 static BOOL warned = FALSE;
4411 ERR("No specular color in source, but destination has one\n");
4415 *( (DWORD *) dest_ptr) = 0xFF000000;
4416 dest_ptr += sizeof(DWORD);
4419 *( (DWORD *) dest_conv) = 0xFF000000;
4420 dest_conv += sizeof(DWORD);
4424 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4426 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4427 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4428 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4429 dest_conv += sizeof(DWORD);
4434 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4436 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4437 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4439 ERR("No source texture, but destination requests one\n");
4440 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4441 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4444 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4446 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4453 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4454 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4455 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4456 dwCount * get_flexible_vertex_size(DestFVF),
4458 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4459 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4466 #undef copy_and_next
4468 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4470 WineDirect3DVertexStridedData strided;
4471 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4472 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4475 ERR("Output vertex declaration not implemented yet\n");
4478 /* Need any context to write to the vbo. */
4479 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4481 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4482 * control the streamIsUP flag, thus restore it afterwards.
4484 This->stateBlock->streamIsUP = FALSE;
4485 memset(&strided, 0, sizeof(strided));
4486 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4487 This->stateBlock->streamIsUP = streamWasUP;
4489 if(vbo || SrcStartIndex) {
4491 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4492 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4494 * Also get the start index in, but only loop over all elements if there's something to add at all.
4496 #define FIXSRC(type) \
4497 if(strided.u.s.type.VBO) { \
4498 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4499 strided.u.s.type.VBO = 0; \
4500 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4502 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4506 if(strided.u.s.type.lpData) { \
4507 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4510 FIXSRC(blendWeights);
4511 FIXSRC(blendMatrixIndices);
4516 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4517 FIXSRC(texCoords[i]);
4530 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4534 * Get / Set Texture Stage States
4535 * TODO: Verify against dx9 definitions
4537 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4539 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4541 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4543 if (Stage >= MAX_TEXTURES) {
4544 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4548 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4549 This->updateStateBlock->textureState[Stage][Type] = Value;
4551 if (This->isRecordingState) {
4552 TRACE("Recording... not performing anything\n");
4556 /* Checked after the assignments to allow proper stateblock recording */
4557 if(oldValue == Value) {
4558 TRACE("App is setting the old value over, nothing to do\n");
4562 if(Stage > This->stateBlock->lowest_disabled_stage &&
4563 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4564 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4565 * Changes in other states are important on disabled stages too
4570 if(Type == WINED3DTSS_COLOROP) {
4573 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4574 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4575 * they have to be disabled
4577 * The current stage is dirtified below.
4579 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4580 TRACE("Additionally dirtifying stage %d\n", i);
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4583 This->stateBlock->lowest_disabled_stage = Stage;
4584 TRACE("New lowest disabled: %d\n", Stage);
4585 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4586 /* Previously disabled stage enabled. Stages above it may need enabling
4587 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4588 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4590 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4593 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4594 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4597 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4600 This->stateBlock->lowest_disabled_stage = i;
4601 TRACE("New lowest disabled: %d\n", i);
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4610 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4613 *pValue = This->updateStateBlock->textureState[Stage][Type];
4620 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 IWineD3DBaseTexture *oldTexture;
4624 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4626 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4627 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4630 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4631 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4632 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4635 oldTexture = This->updateStateBlock->textures[Stage];
4637 if(pTexture != NULL) {
4638 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4640 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4641 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4642 return WINED3DERR_INVALIDCALL;
4644 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4647 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4648 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4650 This->updateStateBlock->changed.textures[Stage] = TRUE;
4651 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4652 This->updateStateBlock->textures[Stage] = pTexture;
4654 /* Handle recording of state blocks */
4655 if (This->isRecordingState) {
4656 TRACE("Recording... not performing anything\n");
4660 if(oldTexture == pTexture) {
4661 TRACE("App is setting the same texture again, nothing to do\n");
4665 /** NOTE: MSDN says that setTexture increases the reference count,
4666 * and that the application must set the texture back to null (or have a leaky application),
4667 * This means we should pass the refcount up to the parent
4668 *******************************/
4669 if (NULL != This->updateStateBlock->textures[Stage]) {
4670 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4671 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4673 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4674 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4675 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4676 * so the COLOROP and ALPHAOP have to be dirtified.
4678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4681 if(bindCount == 1) {
4682 new->baseTexture.sampler = Stage;
4684 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4688 if (NULL != oldTexture) {
4689 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4690 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4692 IWineD3DBaseTexture_Release(oldTexture);
4693 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4698 if(bindCount && old->baseTexture.sampler == Stage) {
4700 /* Have to do a search for the other sampler(s) where the texture is bound to
4701 * Shouldn't happen as long as apps bind a texture only to one stage
4703 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4704 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4705 if(This->updateStateBlock->textures[i] == oldTexture) {
4706 old->baseTexture.sampler = i;
4713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4718 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4721 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4723 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4724 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4727 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4728 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4729 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4732 *ppTexture=This->stateBlock->textures[Stage];
4734 IWineD3DBaseTexture_AddRef(*ppTexture);
4736 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4744 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4745 IWineD3DSurface **ppBackBuffer) {
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4747 IWineD3DSwapChain *swapChain;
4750 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4752 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4753 if (hr == WINED3D_OK) {
4754 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4755 IWineD3DSwapChain_Release(swapChain);
4757 *ppBackBuffer = NULL;
4762 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 WARN("(%p) : stub, calling idirect3d for now\n", This);
4765 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4768 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4770 IWineD3DSwapChain *swapChain;
4773 if(iSwapChain > 0) {
4774 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4775 if (hr == WINED3D_OK) {
4776 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4777 IWineD3DSwapChain_Release(swapChain);
4779 FIXME("(%p) Error getting display mode\n", This);
4782 /* Don't read the real display mode,
4783 but return the stored mode instead. X11 can't change the color
4784 depth, and some apps are pretty angry if they SetDisplayMode from
4785 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4787 Also don't relay to the swapchain because with ddraw it's possible
4788 that there isn't a swapchain at all */
4789 pMode->Width = This->ddraw_width;
4790 pMode->Height = This->ddraw_height;
4791 pMode->Format = This->ddraw_format;
4792 pMode->RefreshRate = 0;
4800 * Stateblock related functions
4803 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4805 IWineD3DStateBlockImpl *object;
4806 HRESULT temp_result;
4809 TRACE("(%p)\n", This);
4811 if (This->isRecordingState) {
4812 return WINED3DERR_INVALIDCALL;
4815 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4816 if (NULL == object ) {
4817 FIXME("(%p)Error allocating memory for stateblock\n", This);
4818 return E_OUTOFMEMORY;
4820 TRACE("(%p) created object %p\n", This, object);
4821 object->wineD3DDevice= This;
4822 /** FIXME: object->parent = parent; **/
4823 object->parent = NULL;
4824 object->blockType = WINED3DSBT_RECORDED;
4826 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4828 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4829 list_init(&object->lightMap[i]);
4832 temp_result = allocate_shader_constants(object);
4833 if (WINED3D_OK != temp_result)
4836 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4837 This->updateStateBlock = object;
4838 This->isRecordingState = TRUE;
4840 TRACE("(%p) recording stateblock %p\n",This , object);
4844 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4847 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4849 if (!This->isRecordingState) {
4850 FIXME("(%p) not recording! returning error\n", This);
4851 *ppStateBlock = NULL;
4852 return WINED3DERR_INVALIDCALL;
4855 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4856 if(object->changed.renderState[i]) {
4857 object->contained_render_states[object->num_contained_render_states] = i;
4858 object->num_contained_render_states++;
4861 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4862 if(object->changed.transform[i]) {
4863 object->contained_transform_states[object->num_contained_transform_states] = i;
4864 object->num_contained_transform_states++;
4867 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4868 if(object->changed.vertexShaderConstantsF[i]) {
4869 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4870 object->num_contained_vs_consts_f++;
4873 for(i = 0; i < MAX_CONST_I; i++) {
4874 if(object->changed.vertexShaderConstantsI[i]) {
4875 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4876 object->num_contained_vs_consts_i++;
4879 for(i = 0; i < MAX_CONST_B; i++) {
4880 if(object->changed.vertexShaderConstantsB[i]) {
4881 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4882 object->num_contained_vs_consts_b++;
4885 for(i = 0; i < MAX_CONST_I; i++) {
4886 if(object->changed.pixelShaderConstantsI[i]) {
4887 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4888 object->num_contained_ps_consts_i++;
4891 for(i = 0; i < MAX_CONST_B; i++) {
4892 if(object->changed.pixelShaderConstantsB[i]) {
4893 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4894 object->num_contained_ps_consts_b++;
4897 for(i = 0; i < MAX_TEXTURES; i++) {
4898 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4899 if(object->changed.textureState[i][j]) {
4900 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4901 object->contained_tss_states[object->num_contained_tss_states].state = j;
4902 object->num_contained_tss_states++;
4906 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4907 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4908 if(object->changed.samplerState[i][j]) {
4909 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4910 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4911 object->num_contained_sampler_states++;
4916 *ppStateBlock = (IWineD3DStateBlock*) object;
4917 This->isRecordingState = FALSE;
4918 This->updateStateBlock = This->stateBlock;
4919 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4920 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4921 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4926 * Scene related functions
4928 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4929 /* At the moment we have no need for any functionality at the beginning
4931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4932 TRACE("(%p)\n", This);
4935 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4936 return WINED3DERR_INVALIDCALL;
4938 This->inScene = TRUE;
4942 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4944 TRACE("(%p)\n", This);
4946 if(!This->inScene) {
4947 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4948 return WINED3DERR_INVALIDCALL;
4951 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4952 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4954 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4958 This->inScene = FALSE;
4962 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4963 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4964 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 IWineD3DSwapChain *swapChain = NULL;
4968 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4970 TRACE("(%p) Presenting the frame\n", This);
4972 for(i = 0 ; i < swapchains ; i ++) {
4974 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4975 TRACE("presentinng chain %d, %p\n", i, swapChain);
4976 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4977 IWineD3DSwapChain_Release(swapChain);
4983 /* Not called from the VTable (internal subroutine) */
4984 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4985 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4986 float Z, DWORD Stencil) {
4987 GLbitfield glMask = 0;
4989 WINED3DRECT curRect;
4991 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4992 UINT drawable_width, drawable_height;
4993 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4995 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4996 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4997 * for the cleared parts, and the untouched parts.
4999 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5000 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5001 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5002 * checking all this if the dest surface is in the drawable anyway.
5004 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5006 if(vp->X != 0 || vp->Y != 0 ||
5007 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5008 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5011 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5012 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5013 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5014 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5015 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5018 if(Count > 0 && pRects && (
5019 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5020 pRects[0].x2 < target->currentDesc.Width ||
5021 pRects[0].y2 < target->currentDesc.Height)) {
5022 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5029 target->get_drawable_size(target, &drawable_width, &drawable_height);
5031 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5034 /* Only set the values up once, as they are not changing */
5035 if (Flags & WINED3DCLEAR_STENCIL) {
5036 glClearStencil(Stencil);
5037 checkGLcall("glClearStencil");
5038 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5039 glStencilMask(0xFFFFFFFF);
5042 if (Flags & WINED3DCLEAR_ZBUFFER) {
5043 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5044 glDepthMask(GL_TRUE);
5046 checkGLcall("glClearDepth");
5047 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5048 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5050 if (vp->X != 0 || vp->Y != 0 ||
5051 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5052 surface_load_ds_location(This->stencilBufferTarget, location);
5054 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5055 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5056 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5057 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5058 surface_load_ds_location(This->stencilBufferTarget, location);
5060 else if (Count > 0 && pRects && (
5061 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5062 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5063 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5064 surface_load_ds_location(This->stencilBufferTarget, location);
5068 if (Flags & WINED3DCLEAR_TARGET) {
5069 TRACE("Clearing screen with glClear to color %x\n", Color);
5070 glClearColor(D3DCOLOR_R(Color),
5074 checkGLcall("glClearColor");
5076 /* Clear ALL colors! */
5077 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5078 glMask = glMask | GL_COLOR_BUFFER_BIT;
5081 vp_rect.left = vp->X;
5082 vp_rect.top = vp->Y;
5083 vp_rect.right = vp->X + vp->Width;
5084 vp_rect.bottom = vp->Y + vp->Height;
5085 if (!(Count > 0 && pRects)) {
5086 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5087 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5089 if(This->render_offscreen) {
5090 glScissor(vp_rect.left, vp_rect.top,
5091 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5093 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5094 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5096 checkGLcall("glScissor");
5098 checkGLcall("glClear");
5100 /* Now process each rect in turn */
5101 for (i = 0; i < Count; i++) {
5102 /* Note gl uses lower left, width/height */
5103 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5104 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5105 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5107 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5108 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5109 curRect.x1, (target->currentDesc.Height - curRect.y2),
5110 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5112 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5113 * The rectangle is not cleared, no error is returned, but further rectanlges are
5114 * still cleared if they are valid
5116 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5117 TRACE("Rectangle with negative dimensions, ignoring\n");
5121 if(This->render_offscreen) {
5122 glScissor(curRect.x1, curRect.y1,
5123 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5125 glScissor(curRect.x1, drawable_height - curRect.y2,
5126 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5128 checkGLcall("glScissor");
5131 checkGLcall("glClear");
5135 /* Restore the old values (why..?) */
5136 if (Flags & WINED3DCLEAR_STENCIL) {
5137 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5139 if (Flags & WINED3DCLEAR_TARGET) {
5140 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5141 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5142 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5143 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5144 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5146 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5147 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5149 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5150 /* TODO: Move the fbo logic into ModifyLocation() */
5151 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5152 target->Flags |= SFLAG_INTEXTURE;
5155 if (Flags & WINED3DCLEAR_ZBUFFER) {
5156 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5157 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5158 surface_modify_ds_location(This->stencilBufferTarget, location);
5166 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5167 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5171 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5172 Count, pRects, Flags, Color, Z, Stencil);
5174 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5175 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5176 /* TODO: What about depth stencil buffers without stencil bits? */
5177 return WINED3DERR_INVALIDCALL;
5180 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5186 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5187 UINT PrimitiveCount) {
5189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5191 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5192 debug_d3dprimitivetype(PrimitiveType),
5193 StartVertex, PrimitiveCount);
5195 if(!This->stateBlock->vertexDecl) {
5196 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5197 return WINED3DERR_INVALIDCALL;
5200 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5201 if(This->stateBlock->streamIsUP) {
5202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5203 This->stateBlock->streamIsUP = FALSE;
5206 if(This->stateBlock->loadBaseVertexIndex != 0) {
5207 This->stateBlock->loadBaseVertexIndex = 0;
5208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5210 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5211 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5212 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5216 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5217 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5218 WINED3DPRIMITIVETYPE PrimitiveType,
5219 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 IWineD3DIndexBuffer *pIB;
5224 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5227 pIB = This->stateBlock->pIndexData;
5229 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5230 * without an index buffer set. (The first time at least...)
5231 * D3D8 simply dies, but I doubt it can do much harm to return
5232 * D3DERR_INVALIDCALL there as well. */
5233 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5234 return WINED3DERR_INVALIDCALL;
5237 if(!This->stateBlock->vertexDecl) {
5238 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5239 return WINED3DERR_INVALIDCALL;
5242 if(This->stateBlock->streamIsUP) {
5243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5244 This->stateBlock->streamIsUP = FALSE;
5246 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5248 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5249 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5250 minIndex, NumVertices, startIndex, primCount);
5252 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5253 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5259 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5260 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5264 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5265 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5271 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5272 UINT VertexStreamZeroStride) {
5273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5274 IWineD3DVertexBuffer *vb;
5276 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5277 debug_d3dprimitivetype(PrimitiveType),
5278 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5280 if(!This->stateBlock->vertexDecl) {
5281 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5282 return WINED3DERR_INVALIDCALL;
5285 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5286 vb = This->stateBlock->streamSource[0];
5287 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5288 if(vb) IWineD3DVertexBuffer_Release(vb);
5289 This->stateBlock->streamOffset[0] = 0;
5290 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5291 This->stateBlock->streamIsUP = TRUE;
5292 This->stateBlock->loadBaseVertexIndex = 0;
5294 /* TODO: Only mark dirty if drawing from a different UP address */
5295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5297 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5298 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5300 /* MSDN specifies stream zero settings must be set to NULL */
5301 This->stateBlock->streamStride[0] = 0;
5302 This->stateBlock->streamSource[0] = NULL;
5304 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5305 * the new stream sources or use UP drawing again
5310 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5311 UINT MinVertexIndex, UINT NumVertices,
5312 UINT PrimitiveCount, CONST void* pIndexData,
5313 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5314 UINT VertexStreamZeroStride) {
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 IWineD3DVertexBuffer *vb;
5318 IWineD3DIndexBuffer *ib;
5320 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5321 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5322 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5323 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5325 if(!This->stateBlock->vertexDecl) {
5326 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5327 return WINED3DERR_INVALIDCALL;
5330 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5336 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5337 vb = This->stateBlock->streamSource[0];
5338 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5339 if(vb) IWineD3DVertexBuffer_Release(vb);
5340 This->stateBlock->streamIsUP = TRUE;
5341 This->stateBlock->streamOffset[0] = 0;
5342 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5344 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5345 This->stateBlock->baseVertexIndex = 0;
5346 This->stateBlock->loadBaseVertexIndex = 0;
5347 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5351 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5353 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5354 This->stateBlock->streamSource[0] = NULL;
5355 This->stateBlock->streamStride[0] = 0;
5356 ib = This->stateBlock->pIndexData;
5358 IWineD3DIndexBuffer_Release(ib);
5359 This->stateBlock->pIndexData = NULL;
5361 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5362 * SetStreamSource to specify a vertex buffer
5368 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5371 /* Mark the state dirty until we have nicer tracking
5372 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5377 This->stateBlock->baseVertexIndex = 0;
5378 This->up_strided = DrawPrimStrideData;
5379 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5380 This->up_strided = NULL;
5384 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5386 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5388 /* Mark the state dirty until we have nicer tracking
5389 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5394 This->stateBlock->streamIsUP = TRUE;
5395 This->stateBlock->baseVertexIndex = 0;
5396 This->up_strided = DrawPrimStrideData;
5397 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5398 This->up_strided = NULL;
5402 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5403 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5404 * not callable by the app directly no parameter validation checks are needed here.
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5407 WINED3DLOCKED_BOX src;
5408 WINED3DLOCKED_BOX dst;
5410 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5412 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5413 * dirtification to improve loading performance.
5415 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5416 if(FAILED(hr)) return hr;
5417 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5419 IWineD3DVolume_UnlockBox(pSourceVolume);
5423 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5425 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5427 IWineD3DVolume_UnlockBox(pSourceVolume);
5429 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5434 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5435 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5437 HRESULT hr = WINED3D_OK;
5438 WINED3DRESOURCETYPE sourceType;
5439 WINED3DRESOURCETYPE destinationType;
5442 /* TODO: think about moving the code into IWineD3DBaseTexture */
5444 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5446 /* verify that the source and destination textures aren't NULL */
5447 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5448 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5449 This, pSourceTexture, pDestinationTexture);
5450 hr = WINED3DERR_INVALIDCALL;
5453 if (pSourceTexture == pDestinationTexture) {
5454 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5455 This, pSourceTexture, pDestinationTexture);
5456 hr = WINED3DERR_INVALIDCALL;
5458 /* Verify that the source and destination textures are the same type */
5459 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5460 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5462 if (sourceType != destinationType) {
5463 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5465 hr = WINED3DERR_INVALIDCALL;
5468 /* check that both textures have the identical numbers of levels */
5469 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5470 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5471 hr = WINED3DERR_INVALIDCALL;
5474 if (WINED3D_OK == hr) {
5476 /* Make sure that the destination texture is loaded */
5477 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5479 /* Update every surface level of the texture */
5480 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5482 switch (sourceType) {
5483 case WINED3DRTYPE_TEXTURE:
5485 IWineD3DSurface *srcSurface;
5486 IWineD3DSurface *destSurface;
5488 for (i = 0 ; i < levels ; ++i) {
5489 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5490 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5491 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5492 IWineD3DSurface_Release(srcSurface);
5493 IWineD3DSurface_Release(destSurface);
5494 if (WINED3D_OK != hr) {
5495 WARN("(%p) : Call to update surface failed\n", This);
5501 case WINED3DRTYPE_CUBETEXTURE:
5503 IWineD3DSurface *srcSurface;
5504 IWineD3DSurface *destSurface;
5505 WINED3DCUBEMAP_FACES faceType;
5507 for (i = 0 ; i < levels ; ++i) {
5508 /* Update each cube face */
5509 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5510 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5511 if (WINED3D_OK != hr) {
5512 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5514 TRACE("Got srcSurface %p\n", srcSurface);
5516 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5517 if (WINED3D_OK != hr) {
5518 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5520 TRACE("Got desrSurface %p\n", destSurface);
5522 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5523 IWineD3DSurface_Release(srcSurface);
5524 IWineD3DSurface_Release(destSurface);
5525 if (WINED3D_OK != hr) {
5526 WARN("(%p) : Call to update surface failed\n", This);
5534 case WINED3DRTYPE_VOLUMETEXTURE:
5536 IWineD3DVolume *srcVolume = NULL;
5537 IWineD3DVolume *destVolume = NULL;
5539 for (i = 0 ; i < levels ; ++i) {
5540 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5541 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5542 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5543 IWineD3DVolume_Release(srcVolume);
5544 IWineD3DVolume_Release(destVolume);
5545 if (WINED3D_OK != hr) {
5546 WARN("(%p) : Call to update volume failed\n", This);
5554 FIXME("(%p) : Unsupported source and destination type\n", This);
5555 hr = WINED3DERR_INVALIDCALL;
5562 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5563 IWineD3DSwapChain *swapChain;
5565 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5566 if(hr == WINED3D_OK) {
5567 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5568 IWineD3DSwapChain_Release(swapChain);
5573 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 /* return a sensible default */
5577 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5578 FIXME("(%p) : stub\n", This);
5582 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5586 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5587 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5588 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5589 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5594 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5598 PALETTEENTRY **palettes;
5600 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5602 if (PaletteNumber >= MAX_PALETTES) {
5603 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5604 return WINED3DERR_INVALIDCALL;
5607 if (PaletteNumber >= This->NumberOfPalettes) {
5608 NewSize = This->NumberOfPalettes;
5611 } while(PaletteNumber >= NewSize);
5612 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5614 ERR("Out of memory!\n");
5615 return E_OUTOFMEMORY;
5617 This->palettes = palettes;
5618 This->NumberOfPalettes = NewSize;
5621 if (!This->palettes[PaletteNumber]) {
5622 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5623 if (!This->palettes[PaletteNumber]) {
5624 ERR("Out of memory!\n");
5625 return E_OUTOFMEMORY;
5629 for (j = 0; j < 256; ++j) {
5630 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5631 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5632 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5633 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5635 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5636 TRACE("(%p) : returning\n", This);
5640 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5643 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5644 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5645 /* What happens in such situation isn't documented; Native seems to silently abort
5646 on such conditions. Return Invalid Call. */
5647 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5648 return WINED3DERR_INVALIDCALL;
5650 for (j = 0; j < 256; ++j) {
5651 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5652 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5653 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5654 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5656 TRACE("(%p) : returning\n", This);
5660 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5663 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5664 (tested with reference rasterizer). Return Invalid Call. */
5665 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5666 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5667 return WINED3DERR_INVALIDCALL;
5669 /*TODO: stateblocks */
5670 if (This->currentPalette != PaletteNumber) {
5671 This->currentPalette = PaletteNumber;
5672 dirtify_p8_texture_samplers(This);
5674 TRACE("(%p) : returning\n", This);
5678 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5680 if (PaletteNumber == NULL) {
5681 WARN("(%p) : returning Invalid Call\n", This);
5682 return WINED3DERR_INVALIDCALL;
5684 /*TODO: stateblocks */
5685 *PaletteNumber = This->currentPalette;
5686 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5690 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5692 static BOOL showFixmes = TRUE;
5694 FIXME("(%p) : stub\n", This);
5698 This->softwareVertexProcessing = bSoftware;
5703 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5705 static BOOL showFixmes = TRUE;
5707 FIXME("(%p) : stub\n", This);
5710 return This->softwareVertexProcessing;
5714 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 IWineD3DSwapChain *swapChain;
5719 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5721 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5722 if(hr == WINED3D_OK){
5723 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5724 IWineD3DSwapChain_Release(swapChain);
5726 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5732 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5734 static BOOL showfixmes = TRUE;
5735 if(nSegments != 0.0f) {
5737 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5744 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5746 static BOOL showfixmes = TRUE;
5748 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5754 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5756 /** TODO: remove casts to IWineD3DSurfaceImpl
5757 * NOTE: move code to surface to accomplish this
5758 ****************************************/
5759 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5760 int srcWidth, srcHeight;
5761 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5762 WINED3DFORMAT destFormat, srcFormat;
5764 int srcLeft, destLeft, destTop;
5765 WINED3DPOOL srcPool, destPool;
5767 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5768 glDescriptor *glDescription = NULL;
5772 CONVERT_TYPES convert = NO_CONVERSION;
5774 WINED3DSURFACE_DESC winedesc;
5776 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5777 memset(&winedesc, 0, sizeof(winedesc));
5778 winedesc.Width = &srcSurfaceWidth;
5779 winedesc.Height = &srcSurfaceHeight;
5780 winedesc.Pool = &srcPool;
5781 winedesc.Format = &srcFormat;
5783 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5785 winedesc.Width = &destSurfaceWidth;
5786 winedesc.Height = &destSurfaceHeight;
5787 winedesc.Pool = &destPool;
5788 winedesc.Format = &destFormat;
5789 winedesc.Size = &destSize;
5791 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5793 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5794 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5795 return WINED3DERR_INVALIDCALL;
5798 /* This call loads the opengl surface directly, instead of copying the surface to the
5799 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5800 * copy in sysmem and use regular surface loading.
5802 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5803 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5804 if(convert != NO_CONVERSION) {
5805 return IWineD3DSurface_BltFast(pDestinationSurface,
5806 pDestPoint ? pDestPoint->x : 0,
5807 pDestPoint ? pDestPoint->y : 0,
5808 pSourceSurface, (RECT *) pSourceRect, 0);
5811 if (destFormat == WINED3DFMT_UNKNOWN) {
5812 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5813 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5815 /* Get the update surface description */
5816 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5819 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5823 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5824 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5825 checkGLcall("glActiveTextureARB");
5828 /* Make sure the surface is loaded and up to date */
5829 IWineD3DSurface_PreLoad(pDestinationSurface);
5831 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5833 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5834 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5835 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5836 srcLeft = pSourceRect ? pSourceRect->left : 0;
5837 destLeft = pDestPoint ? pDestPoint->x : 0;
5838 destTop = pDestPoint ? pDestPoint->y : 0;
5841 /* This function doesn't support compressed textures
5842 the pitch is just bytesPerPixel * width */
5843 if(srcWidth != srcSurfaceWidth || srcLeft ){
5844 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5845 offset += srcLeft * pSrcSurface->bytesPerPixel;
5846 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5848 /* TODO DXT formats */
5850 if(pSourceRect != NULL && pSourceRect->top != 0){
5851 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5853 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5855 ,glDescription->level
5860 ,glDescription->glFormat
5861 ,glDescription->glType
5862 ,IWineD3DSurface_GetData(pSourceSurface)
5866 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5868 /* need to lock the surface to get the data */
5869 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5872 /* TODO: Cube and volume support */
5874 /* not a whole row so we have to do it a line at a time */
5877 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5878 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5880 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5882 glTexSubImage2D(glDescription->target
5883 ,glDescription->level
5888 ,glDescription->glFormat
5889 ,glDescription->glType
5890 ,data /* could be quicker using */
5895 } else { /* Full width, so just write out the whole texture */
5897 if (WINED3DFMT_DXT1 == destFormat ||
5898 WINED3DFMT_DXT2 == destFormat ||
5899 WINED3DFMT_DXT3 == destFormat ||
5900 WINED3DFMT_DXT4 == destFormat ||
5901 WINED3DFMT_DXT5 == destFormat) {
5902 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5903 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5904 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5905 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5906 } if (destFormat != srcFormat) {
5907 FIXME("Updating mixed format compressed texture is not curretly support\n");
5909 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5910 glDescription->level,
5911 glDescription->glFormatInternal,
5916 IWineD3DSurface_GetData(pSourceSurface));
5919 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5924 glTexSubImage2D(glDescription->target
5925 ,glDescription->level
5930 ,glDescription->glFormat
5931 ,glDescription->glType
5932 ,IWineD3DSurface_GetData(pSourceSurface)
5936 checkGLcall("glTexSubImage2D");
5940 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5941 sampler = This->rev_tex_unit_map[0];
5942 if (sampler != -1) {
5943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5949 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5951 struct WineD3DRectPatch *patch;
5955 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5957 if(!(Handle || pRectPatchInfo)) {
5958 /* TODO: Write a test for the return value, thus the FIXME */
5959 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5960 return WINED3DERR_INVALIDCALL;
5964 i = PATCHMAP_HASHFUNC(Handle);
5966 LIST_FOR_EACH(e, &This->patches[i]) {
5967 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5968 if(patch->Handle == Handle) {
5975 TRACE("Patch does not exist. Creating a new one\n");
5976 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5977 patch->Handle = Handle;
5978 list_add_head(&This->patches[i], &patch->entry);
5980 TRACE("Found existing patch %p\n", patch);
5983 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5984 * attributes we have to tesselate, read back, and draw. This needs a patch
5985 * management structure instance. Create one.
5987 * A possible improvement is to check if a vertex shader is used, and if not directly
5990 FIXME("Drawing an uncached patch. This is slow\n");
5991 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5994 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5995 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5996 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5998 TRACE("Tesselation density or patch info changed, retesselating\n");
6000 if(pRectPatchInfo) {
6001 patch->RectPatchInfo = *pRectPatchInfo;
6003 patch->numSegs[0] = pNumSegs[0];
6004 patch->numSegs[1] = pNumSegs[1];
6005 patch->numSegs[2] = pNumSegs[2];
6006 patch->numSegs[3] = pNumSegs[3];
6008 hr = tesselate_rectpatch(This, patch);
6010 WARN("Patch tesselation failed\n");
6012 /* Do not release the handle to store the params of the patch */
6014 HeapFree(GetProcessHeap(), 0, patch);
6020 This->currentPatch = patch;
6021 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6022 This->currentPatch = NULL;
6024 /* Destroy uncached patches */
6026 HeapFree(GetProcessHeap(), 0, patch->mem);
6027 HeapFree(GetProcessHeap(), 0, patch);
6032 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6034 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6035 FIXME("(%p) : Stub\n", This);
6039 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6042 struct WineD3DRectPatch *patch;
6044 TRACE("(%p) Handle(%d)\n", This, Handle);
6046 i = PATCHMAP_HASHFUNC(Handle);
6047 LIST_FOR_EACH(e, &This->patches[i]) {
6048 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6049 if(patch->Handle == Handle) {
6050 TRACE("Deleting patch %p\n", patch);
6051 list_remove(&patch->entry);
6052 HeapFree(GetProcessHeap(), 0, patch->mem);
6053 HeapFree(GetProcessHeap(), 0, patch);
6058 /* TODO: Write a test for the return value */
6059 FIXME("Attempt to destroy nonexistent patch\n");
6060 return WINED3DERR_INVALIDCALL;
6063 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6065 IWineD3DSwapChain *swapchain;
6067 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6068 if (SUCCEEDED(hr)) {
6069 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6076 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6080 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6081 checkGLcall("glGenFramebuffersEXT()");
6083 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6084 checkGLcall("glBindFramebuffer()");
6087 /* TODO: Handle stencil attachments */
6088 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6089 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6091 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6092 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6093 checkGLcall("glFramebufferRenderbufferEXT()");
6095 IWineD3DBaseTextureImpl *texture_impl;
6096 GLenum texttarget, target;
6097 GLint old_binding = 0;
6099 texttarget = depth_stencil_impl->glDescription.target;
6100 if(texttarget == GL_TEXTURE_2D) {
6101 target = GL_TEXTURE_2D;
6102 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6103 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6104 target = GL_TEXTURE_RECTANGLE_ARB;
6105 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6107 target = GL_TEXTURE_CUBE_MAP_ARB;
6108 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6111 IWineD3DSurface_PreLoad(depth_stencil);
6113 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6114 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6115 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6116 glBindTexture(target, old_binding);
6118 /* Update base texture states array */
6119 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6120 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6121 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6122 if (texture_impl->baseTexture.bindCount) {
6123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6126 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6129 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6130 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6131 checkGLcall("glFramebufferTexture2DEXT()");
6135 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6136 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6137 IWineD3DBaseTextureImpl *texture_impl;
6138 GLenum texttarget, target;
6141 texttarget = surface_impl->glDescription.target;
6142 if(texttarget == GL_TEXTURE_2D) {
6143 target = GL_TEXTURE_2D;
6144 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6145 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6146 target = GL_TEXTURE_RECTANGLE_ARB;
6147 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6149 target = GL_TEXTURE_CUBE_MAP_ARB;
6150 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6153 IWineD3DSurface_PreLoad(surface);
6155 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6156 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6157 glBindTexture(target, old_binding);
6159 /* Update base texture states array */
6160 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6161 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6162 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6163 if (texture_impl->baseTexture.bindCount) {
6164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6167 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6170 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6171 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6173 checkGLcall("attach_surface_fbo");
6176 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6178 IWineD3DSwapChain *swapchain;
6180 swapchain = get_swapchain(surface);
6184 TRACE("Surface %p is onscreen\n", surface);
6186 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6188 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6189 buffer = surface_get_gl_buffer(surface, swapchain);
6190 glDrawBuffer(buffer);
6191 checkGLcall("glDrawBuffer()");
6193 TRACE("Surface %p is offscreen\n", surface);
6195 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6197 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6198 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6199 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6200 checkGLcall("glFramebufferRenderbufferEXT");
6204 glEnable(GL_SCISSOR_TEST);
6206 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6208 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6209 rect->x2 - rect->x1, rect->y2 - rect->y1);
6211 checkGLcall("glScissor");
6212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6214 glDisable(GL_SCISSOR_TEST);
6216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6218 glDisable(GL_BLEND);
6219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6221 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6224 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6225 glClear(GL_COLOR_BUFFER_BIT);
6226 checkGLcall("glClear");
6228 if (This->render_offscreen) {
6229 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6231 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6232 checkGLcall("glBindFramebuffer()");
6235 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6236 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6237 glDrawBuffer(GL_BACK);
6238 checkGLcall("glDrawBuffer()");
6244 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6245 unsigned int r, g, b, a;
6248 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6249 destfmt == WINED3DFMT_R8G8B8)
6252 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6254 a = (color & 0xff000000) >> 24;
6255 r = (color & 0x00ff0000) >> 16;
6256 g = (color & 0x0000ff00) >> 8;
6257 b = (color & 0x000000ff) >> 0;
6261 case WINED3DFMT_R5G6B5:
6262 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6269 TRACE("Returning %08x\n", ret);
6272 case WINED3DFMT_X1R5G5B5:
6273 case WINED3DFMT_A1R5G5B5:
6282 TRACE("Returning %08x\n", ret);
6286 TRACE("Returning %08x\n", a);
6289 case WINED3DFMT_X4R4G4B4:
6290 case WINED3DFMT_A4R4G4B4:
6299 TRACE("Returning %08x\n", ret);
6302 case WINED3DFMT_R3G3B2:
6309 TRACE("Returning %08x\n", ret);
6312 case WINED3DFMT_X8B8G8R8:
6313 case WINED3DFMT_A8B8G8R8:
6318 TRACE("Returning %08x\n", ret);
6321 case WINED3DFMT_A2R10G10B10:
6323 r = (r * 1024) / 256;
6324 g = (g * 1024) / 256;
6325 b = (b * 1024) / 256;
6330 TRACE("Returning %08x\n", ret);
6333 case WINED3DFMT_A2B10G10R10:
6335 r = (r * 1024) / 256;
6336 g = (g * 1024) / 256;
6337 b = (b * 1024) / 256;
6342 TRACE("Returning %08x\n", ret);
6346 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6351 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6353 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6355 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6357 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6358 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6359 return WINED3DERR_INVALIDCALL;
6362 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6363 color_fill_fbo(iface, pSurface, pRect, color);
6366 /* Just forward this to the DirectDraw blitting engine */
6367 memset(&BltFx, 0, sizeof(BltFx));
6368 BltFx.dwSize = sizeof(BltFx);
6369 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6370 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6374 /* rendertarget and depth stencil functions */
6375 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6378 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6379 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6380 return WINED3DERR_INVALIDCALL;
6383 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6384 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6385 /* Note inc ref on returned surface */
6386 if(*ppRenderTarget != NULL)
6387 IWineD3DSurface_AddRef(*ppRenderTarget);
6391 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6393 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6394 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6395 IWineD3DSwapChainImpl *Swapchain;
6398 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6400 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6401 if(hr != WINED3D_OK) {
6402 ERR("Can't get the swapchain\n");
6406 /* Make sure to release the swapchain */
6407 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6409 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6410 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6411 return WINED3DERR_INVALIDCALL;
6413 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6414 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6415 return WINED3DERR_INVALIDCALL;
6418 if(Swapchain->frontBuffer != Front) {
6419 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6421 if(Swapchain->frontBuffer)
6422 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6423 Swapchain->frontBuffer = Front;
6425 if(Swapchain->frontBuffer) {
6426 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6430 if(Back && !Swapchain->backBuffer) {
6431 /* We need memory for the back buffer array - only one back buffer this way */
6432 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6433 if(!Swapchain->backBuffer) {
6434 ERR("Out of memory\n");
6435 return E_OUTOFMEMORY;
6439 if(Swapchain->backBuffer[0] != Back) {
6440 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6442 /* What to do about the context here in the case of multithreading? Not sure.
6443 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6446 if(!Swapchain->backBuffer[0]) {
6447 /* GL was told to draw to the front buffer at creation,
6450 glDrawBuffer(GL_BACK);
6451 checkGLcall("glDrawBuffer(GL_BACK)");
6452 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6453 Swapchain->presentParms.BackBufferCount = 1;
6455 /* That makes problems - disable for now */
6456 /* glDrawBuffer(GL_FRONT); */
6457 checkGLcall("glDrawBuffer(GL_FRONT)");
6458 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6459 Swapchain->presentParms.BackBufferCount = 0;
6463 if(Swapchain->backBuffer[0])
6464 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6465 Swapchain->backBuffer[0] = Back;
6467 if(Swapchain->backBuffer[0]) {
6468 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6470 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6471 Swapchain->backBuffer = NULL;
6479 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6481 *ppZStencilSurface = This->stencilBufferTarget;
6482 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6484 if(*ppZStencilSurface != NULL) {
6485 /* Note inc ref on returned surface */
6486 IWineD3DSurface_AddRef(*ppZStencilSurface);
6489 return WINED3DERR_NOTFOUND;
6493 /* TODO: Handle stencil attachments */
6494 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6497 TRACE("Set depth stencil to %p\n", depth_stencil);
6499 if (depth_stencil) {
6500 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6502 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6503 checkGLcall("glFramebufferTexture2DEXT()");
6507 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6510 TRACE("Set render target %u to %p\n", idx, render_target);
6512 if (render_target) {
6513 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6514 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6516 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6517 checkGLcall("glFramebufferTexture2DEXT()");
6519 This->draw_buffers[idx] = GL_NONE;
6523 static void check_fbo_status(IWineD3DDevice *iface) {
6524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6527 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6528 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6529 TRACE("FBO complete\n");
6531 IWineD3DSurfaceImpl *attachment;
6533 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6535 /* Dump the FBO attachments */
6536 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6537 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i];
6539 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6540 attachment->pow2Width, attachment->pow2Height);
6543 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment;
6545 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6546 attachment->pow2Width, attachment->pow2Height);
6551 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6553 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6554 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6556 if (!ds_impl) return FALSE;
6558 if (ds_impl->current_renderbuffer) {
6559 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6560 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6563 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6564 rt_impl->pow2Height != ds_impl->pow2Height);
6567 void apply_fbo_state(IWineD3DDevice *iface) {
6568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6569 WineD3DContext *context = This->activeContext;
6572 if (This->render_offscreen) {
6573 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo);
6575 /* Apply render targets */
6576 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6577 IWineD3DSurface *render_target = This->render_targets[i];
6578 if (context->fbo_color_attachments[i] != render_target) {
6579 set_render_target_fbo(iface, i, render_target);
6580 context->fbo_color_attachments[i] = render_target;
6584 /* Apply depth targets */
6585 if (context->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6586 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6587 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6589 if (This->stencilBufferTarget) {
6590 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6592 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6593 context->fbo_depth_attachment = This->stencilBufferTarget;
6596 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6599 check_fbo_status(iface);
6602 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6603 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6605 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6606 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6608 POINT offset = {0, 0};
6610 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6611 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6612 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6613 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6616 case WINED3DTEXF_LINEAR:
6617 gl_filter = GL_LINEAR;
6621 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6622 case WINED3DTEXF_NONE:
6623 case WINED3DTEXF_POINT:
6624 gl_filter = GL_NEAREST;
6628 /* Attach src surface to src fbo */
6629 src_swapchain = get_swapchain(src_surface);
6630 if (src_swapchain) {
6631 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6633 TRACE("Source surface %p is onscreen\n", src_surface);
6634 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6635 /* Make sure the drawable is up to date. In the offscreen case
6636 * attach_surface_fbo() implicitly takes care of this. */
6637 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6639 if(buffer == GL_FRONT) {
6642 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6643 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6644 h = windowsize.bottom - windowsize.top;
6645 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6646 src_rect->y1 = offset.y + h - src_rect->y1;
6647 src_rect->y2 = offset.y + h - src_rect->y2;
6649 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6650 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6654 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6655 glReadBuffer(buffer);
6656 checkGLcall("glReadBuffer()");
6658 TRACE("Source surface %p is offscreen\n", src_surface);
6660 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6661 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6662 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6663 checkGLcall("glReadBuffer()");
6664 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6665 checkGLcall("glFramebufferRenderbufferEXT");
6669 /* Attach dst surface to dst fbo */
6670 dst_swapchain = get_swapchain(dst_surface);
6671 if (dst_swapchain) {
6672 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6674 TRACE("Destination surface %p is onscreen\n", dst_surface);
6675 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6676 /* Make sure the drawable is up to date. In the offscreen case
6677 * attach_surface_fbo() implicitly takes care of this. */
6678 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6680 if(buffer == GL_FRONT) {
6683 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6684 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6685 h = windowsize.bottom - windowsize.top;
6686 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6687 dst_rect->y1 = offset.y + h - dst_rect->y1;
6688 dst_rect->y2 = offset.y + h - dst_rect->y2;
6690 /* Screen coords = window coords, surface height = window height */
6691 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6692 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6696 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6697 glDrawBuffer(buffer);
6698 checkGLcall("glDrawBuffer()");
6700 TRACE("Destination surface %p is offscreen\n", dst_surface);
6702 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6703 if(!src_swapchain) {
6704 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6708 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6709 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6710 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6711 checkGLcall("glDrawBuffer()");
6712 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6713 checkGLcall("glFramebufferRenderbufferEXT");
6715 glDisable(GL_SCISSOR_TEST);
6716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6719 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6720 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6721 checkGLcall("glBlitFramebuffer()");
6723 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6724 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6725 checkGLcall("glBlitFramebuffer()");
6728 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6730 if (This->render_offscreen) {
6731 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6733 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6734 checkGLcall("glBindFramebuffer()");
6737 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6738 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6739 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6740 glDrawBuffer(GL_BACK);
6741 checkGLcall("glDrawBuffer()");
6746 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6748 WINED3DVIEWPORT viewport;
6750 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6752 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6753 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6754 This, RenderTargetIndex, GL_LIMITS(buffers));
6755 return WINED3DERR_INVALIDCALL;
6758 /* MSDN says that null disables the render target
6759 but a device must always be associated with a render target
6760 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6762 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6763 FIXME("Trying to set render target 0 to NULL\n");
6764 return WINED3DERR_INVALIDCALL;
6766 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6767 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);
6768 return WINED3DERR_INVALIDCALL;
6771 /* If we are trying to set what we already have, don't bother */
6772 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6773 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6776 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6777 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6778 This->render_targets[RenderTargetIndex] = pRenderTarget;
6780 /* Render target 0 is special */
6781 if(RenderTargetIndex == 0) {
6782 /* Finally, reset the viewport as the MSDN states. */
6783 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6784 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6787 viewport.MaxZ = 1.0f;
6788 viewport.MinZ = 0.0f;
6789 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6790 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6791 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6798 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6800 HRESULT hr = WINED3D_OK;
6801 IWineD3DSurface *tmp;
6803 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6805 if (pNewZStencil == This->stencilBufferTarget) {
6806 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6808 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6809 * depending on the renter target implementation being used.
6810 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6811 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6812 * stencil buffer and incur an extra memory overhead
6813 ******************************************************/
6815 if (This->stencilBufferTarget) {
6816 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6817 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6818 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6821 tmp = This->stencilBufferTarget;
6822 This->stencilBufferTarget = pNewZStencil;
6823 /* should we be calling the parent or the wined3d surface? */
6824 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6825 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6828 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6829 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6839 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6840 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6842 /* TODO: the use of Impl is deprecated. */
6843 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6844 WINED3DLOCKED_RECT lockedRect;
6846 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6848 /* some basic validation checks */
6849 if(This->cursorTexture) {
6850 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6852 glDeleteTextures(1, &This->cursorTexture);
6854 This->cursorTexture = 0;
6857 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6858 This->haveHardwareCursor = TRUE;
6860 This->haveHardwareCursor = FALSE;
6863 WINED3DLOCKED_RECT rect;
6865 /* MSDN: Cursor must be A8R8G8B8 */
6866 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6867 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6868 return WINED3DERR_INVALIDCALL;
6871 /* MSDN: Cursor must be smaller than the display mode */
6872 if(pSur->currentDesc.Width > This->ddraw_width ||
6873 pSur->currentDesc.Height > This->ddraw_height) {
6874 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);
6875 return WINED3DERR_INVALIDCALL;
6878 if (!This->haveHardwareCursor) {
6879 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6881 /* Do not store the surface's pointer because the application may
6882 * release it after setting the cursor image. Windows doesn't
6883 * addref the set surface, so we can't do this either without
6884 * creating circular refcount dependencies. Copy out the gl texture
6887 This->cursorWidth = pSur->currentDesc.Width;
6888 This->cursorHeight = pSur->currentDesc.Height;
6889 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6891 const GlPixelFormatDesc *glDesc;
6892 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6893 char *mem, *bits = (char *)rect.pBits;
6894 GLint intfmt = glDesc->glInternal;
6895 GLint format = glDesc->glFormat;
6896 GLint type = glDesc->glType;
6897 INT height = This->cursorHeight;
6898 INT width = This->cursorWidth;
6899 INT bpp = tableEntry->bpp;
6902 /* Reformat the texture memory (pitch and width can be
6904 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6905 for(i = 0; i < height; i++)
6906 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6907 IWineD3DSurface_UnlockRect(pCursorBitmap);
6910 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6911 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6912 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6915 /* Make sure that a proper texture unit is selected */
6916 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6917 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6918 checkGLcall("glActiveTextureARB");
6920 sampler = This->rev_tex_unit_map[0];
6921 if (sampler != -1) {
6922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6924 /* Create a new cursor texture */
6925 glGenTextures(1, &This->cursorTexture);
6926 checkGLcall("glGenTextures");
6927 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6928 checkGLcall("glBindTexture");
6929 /* Copy the bitmap memory into the cursor texture */
6930 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6931 HeapFree(GetProcessHeap(), 0, mem);
6932 checkGLcall("glTexImage2D");
6934 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6935 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6936 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6943 FIXME("A cursor texture was not returned.\n");
6944 This->cursorTexture = 0;
6949 /* Draw a hardware cursor */
6950 ICONINFO cursorInfo;
6952 /* Create and clear maskBits because it is not needed for
6953 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6955 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6956 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6957 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6958 WINED3DLOCK_NO_DIRTY_UPDATE |
6959 WINED3DLOCK_READONLY
6961 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6962 pSur->currentDesc.Height);
6964 cursorInfo.fIcon = FALSE;
6965 cursorInfo.xHotspot = XHotSpot;
6966 cursorInfo.yHotspot = YHotSpot;
6967 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6968 pSur->currentDesc.Height, 1,
6970 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6971 pSur->currentDesc.Height, 1,
6972 32, lockedRect.pBits);
6973 IWineD3DSurface_UnlockRect(pCursorBitmap);
6974 /* Create our cursor and clean up. */
6975 cursor = CreateIconIndirect(&cursorInfo);
6977 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6978 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6979 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6980 This->hardwareCursor = cursor;
6981 HeapFree(GetProcessHeap(), 0, maskBits);
6985 This->xHotSpot = XHotSpot;
6986 This->yHotSpot = YHotSpot;
6990 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6992 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6994 This->xScreenSpace = XScreenSpace;
6995 This->yScreenSpace = YScreenSpace;
7001 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7003 BOOL oldVisible = This->bCursorVisible;
7006 TRACE("(%p) : visible(%d)\n", This, bShow);
7009 * When ShowCursor is first called it should make the cursor appear at the OS's last
7010 * known cursor position. Because of this, some applications just repetitively call
7011 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7014 This->xScreenSpace = pt.x;
7015 This->yScreenSpace = pt.y;
7017 if (This->haveHardwareCursor) {
7018 This->bCursorVisible = bShow;
7020 SetCursor(This->hardwareCursor);
7026 if (This->cursorTexture)
7027 This->bCursorVisible = bShow;
7033 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7035 IWineD3DResourceImpl *resource;
7036 TRACE("(%p) : state (%u)\n", This, This->state);
7038 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7039 switch (This->state) {
7042 case WINED3DERR_DEVICELOST:
7044 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7045 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7046 return WINED3DERR_DEVICENOTRESET;
7048 return WINED3DERR_DEVICELOST;
7050 case WINED3DERR_DRIVERINTERNALERROR:
7051 return WINED3DERR_DRIVERINTERNALERROR;
7055 return WINED3DERR_DRIVERINTERNALERROR;
7059 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7061 /** FIXME: Resource tracking needs to be done,
7062 * The closes we can do to this is set the priorities of all managed textures low
7063 * and then reset them.
7064 ***********************************************************/
7065 FIXME("(%p) : stub\n", This);
7069 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7070 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7072 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7073 if(surface->Flags & SFLAG_DIBSECTION) {
7074 /* Release the DC */
7075 SelectObject(surface->hDC, surface->dib.holdbitmap);
7076 DeleteDC(surface->hDC);
7077 /* Release the DIB section */
7078 DeleteObject(surface->dib.DIBsection);
7079 surface->dib.bitmap_data = NULL;
7080 surface->resource.allocatedMemory = NULL;
7081 surface->Flags &= ~SFLAG_DIBSECTION;
7083 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7084 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7085 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7086 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7087 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7088 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7090 surface->pow2Width = surface->pow2Height = 1;
7091 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7092 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7094 surface->glRect.left = 0;
7095 surface->glRect.top = 0;
7096 surface->glRect.right = surface->pow2Width;
7097 surface->glRect.bottom = surface->pow2Height;
7099 if(surface->glDescription.textureName) {
7100 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7102 glDeleteTextures(1, &surface->glDescription.textureName);
7104 surface->glDescription.textureName = 0;
7105 surface->Flags &= ~SFLAG_CLIENT;
7107 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7108 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7109 surface->Flags |= SFLAG_NONPOW2;
7111 surface->Flags &= ~SFLAG_NONPOW2;
7113 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7114 surface->resource.allocatedMemory = NULL;
7115 surface->resource.heapMemory = NULL;
7116 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7117 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7118 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7119 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7121 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7125 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7126 TRACE("Unloading resource %p\n", resource);
7127 IWineD3DResource_UnLoad(resource);
7128 IWineD3DResource_Release(resource);
7132 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7134 WINED3DDISPLAYMODE m;
7137 /* All Windowed modes are supported, as is leaving the current mode */
7138 if(pp->Windowed) return TRUE;
7139 if(!pp->BackBufferWidth) return TRUE;
7140 if(!pp->BackBufferHeight) return TRUE;
7142 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7143 for(i = 0; i < count; i++) {
7144 memset(&m, 0, sizeof(m));
7145 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7147 ERR("EnumAdapterModes failed\n");
7149 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7150 /* Mode found, it is supported */
7154 /* Mode not found -> not supported */
7158 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7160 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7162 IWineD3DBaseShaderImpl *shader;
7164 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7165 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7166 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7170 if(This->depth_blt_texture) {
7171 glDeleteTextures(1, &This->depth_blt_texture);
7172 This->depth_blt_texture = 0;
7174 if (This->depth_blt_rb) {
7175 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7176 This->depth_blt_rb = 0;
7177 This->depth_blt_rb_w = 0;
7178 This->depth_blt_rb_h = 0;
7180 This->blitter->free_private(iface);
7181 This->frag_pipe->free_private(iface);
7182 This->shader_backend->shader_free_private(iface);
7184 for (i = 0; i < GL_LIMITS(textures); i++) {
7185 /* Textures are recreated below */
7186 glDeleteTextures(1, &This->dummyTextureName[i]);
7187 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7188 This->dummyTextureName[i] = 0;
7192 while(This->numContexts) {
7193 DestroyContext(This, This->contexts[0]);
7195 This->activeContext = NULL;
7196 HeapFree(GetProcessHeap(), 0, swapchain->context);
7197 swapchain->context = NULL;
7198 swapchain->num_contexts = 0;
7201 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7203 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7205 IWineD3DSurfaceImpl *target;
7207 /* Recreate the primary swapchain's context */
7208 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7209 if(swapchain->backBuffer) {
7210 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7212 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7214 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7215 &swapchain->presentParms);
7216 swapchain->num_contexts = 1;
7217 This->activeContext = swapchain->context[0];
7219 create_dummy_textures(This);
7221 hr = This->shader_backend->shader_alloc_private(iface);
7223 ERR("Failed to recreate shader private data\n");
7226 hr = This->frag_pipe->alloc_private(iface);
7228 TRACE("Fragment pipeline private data couldn't be allocated\n");
7231 hr = This->blitter->alloc_private(iface);
7233 TRACE("Blitter private data couldn't be allocated\n");
7240 This->blitter->free_private(iface);
7241 This->frag_pipe->free_private(iface);
7242 This->shader_backend->shader_free_private(iface);
7246 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7248 IWineD3DSwapChainImpl *swapchain;
7250 BOOL DisplayModeChanged = FALSE;
7251 WINED3DDISPLAYMODE mode;
7252 TRACE("(%p)\n", This);
7254 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7256 ERR("Failed to get the first implicit swapchain\n");
7260 if(!is_display_mode_supported(This, pPresentationParameters)) {
7261 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7262 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7263 pPresentationParameters->BackBufferHeight);
7264 return WINED3DERR_INVALIDCALL;
7267 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7268 * on an existing gl context, so there's no real need for recreation.
7270 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7272 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7274 TRACE("New params:\n");
7275 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7276 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7277 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7278 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7279 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7280 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7281 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7282 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7283 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7284 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7285 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7286 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7287 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7289 /* No special treatment of these parameters. Just store them */
7290 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7291 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7292 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7293 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7295 /* What to do about these? */
7296 if(pPresentationParameters->BackBufferCount != 0 &&
7297 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7298 ERR("Cannot change the back buffer count yet\n");
7300 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7301 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7302 ERR("Cannot change the back buffer format yet\n");
7304 if(pPresentationParameters->hDeviceWindow != NULL &&
7305 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7306 ERR("Cannot change the device window yet\n");
7308 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7309 ERR("What do do about a changed auto depth stencil parameter?\n");
7312 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7314 if(pPresentationParameters->Windowed) {
7315 mode.Width = swapchain->orig_width;
7316 mode.Height = swapchain->orig_height;
7317 mode.RefreshRate = 0;
7318 mode.Format = swapchain->presentParms.BackBufferFormat;
7320 mode.Width = pPresentationParameters->BackBufferWidth;
7321 mode.Height = pPresentationParameters->BackBufferHeight;
7322 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7323 mode.Format = swapchain->presentParms.BackBufferFormat;
7326 /* Should Width == 800 && Height == 0 set 800x600? */
7327 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7328 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7329 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7336 vp.Width = pPresentationParameters->BackBufferWidth;
7337 vp.Height = pPresentationParameters->BackBufferHeight;
7341 if(!pPresentationParameters->Windowed) {
7342 DisplayModeChanged = TRUE;
7344 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7345 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7347 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7348 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7349 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7351 if(This->auto_depth_stencil_buffer) {
7352 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7356 /* Now set the new viewport */
7357 IWineD3DDevice_SetViewport(iface, &vp);
7360 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7361 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7362 DisplayModeChanged) {
7364 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7366 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7367 if(swapchain->presentParms.Windowed) {
7368 /* switch from windowed to fs */
7369 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7370 pPresentationParameters->BackBufferWidth,
7371 pPresentationParameters->BackBufferHeight);
7373 /* Fullscreen -> fullscreen mode change */
7374 MoveWindow(swapchain->win_handle, 0, 0,
7375 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7378 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7379 /* Fullscreen -> windowed switch */
7380 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7382 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7383 } else if(!pPresentationParameters->Windowed) {
7384 DWORD style = This->style, exStyle = This->exStyle;
7385 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7386 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7387 * Reset to clear up their mess. Guild Wars also loses the device during that.
7391 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7392 pPresentationParameters->BackBufferWidth,
7393 pPresentationParameters->BackBufferHeight);
7394 This->style = style;
7395 This->exStyle = exStyle;
7398 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7400 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7403 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7404 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7406 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7412 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7414 /** FIXME: always true at the moment **/
7415 if(!bEnableDialogs) {
7416 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7422 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7424 TRACE("(%p) : pParameters %p\n", This, pParameters);
7426 *pParameters = This->createParms;
7430 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7431 IWineD3DSwapChain *swapchain;
7433 TRACE("Relaying to swapchain\n");
7435 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7436 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7437 IWineD3DSwapChain_Release(swapchain);
7442 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7443 IWineD3DSwapChain *swapchain;
7445 TRACE("Relaying to swapchain\n");
7447 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7448 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7449 IWineD3DSwapChain_Release(swapchain);
7455 /** ********************************************************
7456 * Notification functions
7457 ** ********************************************************/
7458 /** This function must be called in the release of a resource when ref == 0,
7459 * the contents of resource must still be correct,
7460 * any handles to other resource held by the caller must be closed
7461 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7462 *****************************************************/
7463 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7466 TRACE("(%p) : Adding Resource %p\n", This, resource);
7467 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7470 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7473 TRACE("(%p) : Removing resource %p\n", This, resource);
7475 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7479 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7483 TRACE("(%p) : resource %p\n", This, resource);
7484 switch(IWineD3DResource_GetType(resource)){
7485 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7486 case WINED3DRTYPE_SURFACE: {
7489 /* Cleanup any FBO attachments if d3d is enabled */
7490 if(This->d3d_initialized) {
7491 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7492 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7494 TRACE("Last active render target destroyed\n");
7495 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7496 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7497 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7498 * and the lastActiveRenderTarget member shouldn't matter
7501 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7502 TRACE("Activating primary back buffer\n");
7503 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7504 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7505 /* Single buffering environment */
7506 TRACE("Activating primary front buffer\n");
7507 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7509 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7510 /* Implicit render target destroyed, that means the device is being destroyed
7511 * whatever we set here, it shouldn't matter
7513 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7516 /* May happen during ddraw uninitialization */
7517 TRACE("Render target set, but swapchain does not exist!\n");
7518 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7522 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7523 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7524 This->render_targets[i] = NULL;
7527 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7528 This->stencilBufferTarget = NULL;
7531 for (i = 0; i < This->numContexts; ++i) {
7533 for (j = 0; j < GL_LIMITS(buffers); ++j) {
7534 if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) {
7535 This->contexts[i]->fbo_color_attachments[j] = NULL;
7538 if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7539 This->contexts[i]->fbo_depth_attachment = NULL;
7546 case WINED3DRTYPE_TEXTURE:
7547 case WINED3DRTYPE_CUBETEXTURE:
7548 case WINED3DRTYPE_VOLUMETEXTURE:
7549 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7550 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7551 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7552 This->stateBlock->textures[counter] = NULL;
7554 if (This->updateStateBlock != This->stateBlock ){
7555 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7556 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7557 This->updateStateBlock->textures[counter] = NULL;
7562 case WINED3DRTYPE_VOLUME:
7563 /* TODO: nothing really? */
7565 case WINED3DRTYPE_VERTEXBUFFER:
7566 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7569 TRACE("Cleaning up stream pointers\n");
7571 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7572 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7573 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7575 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7576 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7577 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7578 This->updateStateBlock->streamSource[streamNumber] = 0;
7579 /* Set changed flag? */
7582 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) */
7583 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7584 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7585 This->stateBlock->streamSource[streamNumber] = 0;
7591 case WINED3DRTYPE_INDEXBUFFER:
7592 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7593 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7594 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7595 This->updateStateBlock->pIndexData = NULL;
7598 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7599 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7600 This->stateBlock->pIndexData = NULL;
7606 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7611 /* Remove the resource from the resourceStore */
7612 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7614 TRACE("Resource released\n");
7618 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7620 IWineD3DResourceImpl *resource, *cursor;
7622 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7624 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7625 TRACE("enumerating resource %p\n", resource);
7626 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7627 ret = pCallback((IWineD3DResource *) resource, pData);
7628 if(ret == S_FALSE) {
7629 TRACE("Canceling enumeration\n");
7636 /**********************************************************
7637 * IWineD3DDevice VTbl follows
7638 **********************************************************/
7640 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7642 /*** IUnknown methods ***/
7643 IWineD3DDeviceImpl_QueryInterface,
7644 IWineD3DDeviceImpl_AddRef,
7645 IWineD3DDeviceImpl_Release,
7646 /*** IWineD3DDevice methods ***/
7647 IWineD3DDeviceImpl_GetParent,
7648 /*** Creation methods**/
7649 IWineD3DDeviceImpl_CreateVertexBuffer,
7650 IWineD3DDeviceImpl_CreateIndexBuffer,
7651 IWineD3DDeviceImpl_CreateStateBlock,
7652 IWineD3DDeviceImpl_CreateSurface,
7653 IWineD3DDeviceImpl_CreateTexture,
7654 IWineD3DDeviceImpl_CreateVolumeTexture,
7655 IWineD3DDeviceImpl_CreateVolume,
7656 IWineD3DDeviceImpl_CreateCubeTexture,
7657 IWineD3DDeviceImpl_CreateQuery,
7658 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7659 IWineD3DDeviceImpl_CreateVertexDeclaration,
7660 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7661 IWineD3DDeviceImpl_CreateVertexShader,
7662 IWineD3DDeviceImpl_CreatePixelShader,
7663 IWineD3DDeviceImpl_CreatePalette,
7664 /*** Odd functions **/
7665 IWineD3DDeviceImpl_Init3D,
7666 IWineD3DDeviceImpl_InitGDI,
7667 IWineD3DDeviceImpl_Uninit3D,
7668 IWineD3DDeviceImpl_UninitGDI,
7669 IWineD3DDeviceImpl_SetMultithreaded,
7670 IWineD3DDeviceImpl_EvictManagedResources,
7671 IWineD3DDeviceImpl_GetAvailableTextureMem,
7672 IWineD3DDeviceImpl_GetBackBuffer,
7673 IWineD3DDeviceImpl_GetCreationParameters,
7674 IWineD3DDeviceImpl_GetDeviceCaps,
7675 IWineD3DDeviceImpl_GetDirect3D,
7676 IWineD3DDeviceImpl_GetDisplayMode,
7677 IWineD3DDeviceImpl_SetDisplayMode,
7678 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7679 IWineD3DDeviceImpl_GetRasterStatus,
7680 IWineD3DDeviceImpl_GetSwapChain,
7681 IWineD3DDeviceImpl_Reset,
7682 IWineD3DDeviceImpl_SetDialogBoxMode,
7683 IWineD3DDeviceImpl_SetCursorProperties,
7684 IWineD3DDeviceImpl_SetCursorPosition,
7685 IWineD3DDeviceImpl_ShowCursor,
7686 IWineD3DDeviceImpl_TestCooperativeLevel,
7687 /*** Getters and setters **/
7688 IWineD3DDeviceImpl_SetClipPlane,
7689 IWineD3DDeviceImpl_GetClipPlane,
7690 IWineD3DDeviceImpl_SetClipStatus,
7691 IWineD3DDeviceImpl_GetClipStatus,
7692 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7693 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7694 IWineD3DDeviceImpl_SetDepthStencilSurface,
7695 IWineD3DDeviceImpl_GetDepthStencilSurface,
7696 IWineD3DDeviceImpl_SetFVF,
7697 IWineD3DDeviceImpl_GetFVF,
7698 IWineD3DDeviceImpl_SetGammaRamp,
7699 IWineD3DDeviceImpl_GetGammaRamp,
7700 IWineD3DDeviceImpl_SetIndices,
7701 IWineD3DDeviceImpl_GetIndices,
7702 IWineD3DDeviceImpl_SetBaseVertexIndex,
7703 IWineD3DDeviceImpl_GetBaseVertexIndex,
7704 IWineD3DDeviceImpl_SetLight,
7705 IWineD3DDeviceImpl_GetLight,
7706 IWineD3DDeviceImpl_SetLightEnable,
7707 IWineD3DDeviceImpl_GetLightEnable,
7708 IWineD3DDeviceImpl_SetMaterial,
7709 IWineD3DDeviceImpl_GetMaterial,
7710 IWineD3DDeviceImpl_SetNPatchMode,
7711 IWineD3DDeviceImpl_GetNPatchMode,
7712 IWineD3DDeviceImpl_SetPaletteEntries,
7713 IWineD3DDeviceImpl_GetPaletteEntries,
7714 IWineD3DDeviceImpl_SetPixelShader,
7715 IWineD3DDeviceImpl_GetPixelShader,
7716 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7717 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7718 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7719 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7720 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7721 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7722 IWineD3DDeviceImpl_SetRenderState,
7723 IWineD3DDeviceImpl_GetRenderState,
7724 IWineD3DDeviceImpl_SetRenderTarget,
7725 IWineD3DDeviceImpl_GetRenderTarget,
7726 IWineD3DDeviceImpl_SetFrontBackBuffers,
7727 IWineD3DDeviceImpl_SetSamplerState,
7728 IWineD3DDeviceImpl_GetSamplerState,
7729 IWineD3DDeviceImpl_SetScissorRect,
7730 IWineD3DDeviceImpl_GetScissorRect,
7731 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7732 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7733 IWineD3DDeviceImpl_SetStreamSource,
7734 IWineD3DDeviceImpl_GetStreamSource,
7735 IWineD3DDeviceImpl_SetStreamSourceFreq,
7736 IWineD3DDeviceImpl_GetStreamSourceFreq,
7737 IWineD3DDeviceImpl_SetTexture,
7738 IWineD3DDeviceImpl_GetTexture,
7739 IWineD3DDeviceImpl_SetTextureStageState,
7740 IWineD3DDeviceImpl_GetTextureStageState,
7741 IWineD3DDeviceImpl_SetTransform,
7742 IWineD3DDeviceImpl_GetTransform,
7743 IWineD3DDeviceImpl_SetVertexDeclaration,
7744 IWineD3DDeviceImpl_GetVertexDeclaration,
7745 IWineD3DDeviceImpl_SetVertexShader,
7746 IWineD3DDeviceImpl_GetVertexShader,
7747 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7748 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7749 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7750 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7751 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7752 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7753 IWineD3DDeviceImpl_SetViewport,
7754 IWineD3DDeviceImpl_GetViewport,
7755 IWineD3DDeviceImpl_MultiplyTransform,
7756 IWineD3DDeviceImpl_ValidateDevice,
7757 IWineD3DDeviceImpl_ProcessVertices,
7758 /*** State block ***/
7759 IWineD3DDeviceImpl_BeginStateBlock,
7760 IWineD3DDeviceImpl_EndStateBlock,
7761 /*** Scene management ***/
7762 IWineD3DDeviceImpl_BeginScene,
7763 IWineD3DDeviceImpl_EndScene,
7764 IWineD3DDeviceImpl_Present,
7765 IWineD3DDeviceImpl_Clear,
7767 IWineD3DDeviceImpl_DrawPrimitive,
7768 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7769 IWineD3DDeviceImpl_DrawPrimitiveUP,
7770 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7771 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7772 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7773 IWineD3DDeviceImpl_DrawRectPatch,
7774 IWineD3DDeviceImpl_DrawTriPatch,
7775 IWineD3DDeviceImpl_DeletePatch,
7776 IWineD3DDeviceImpl_ColorFill,
7777 IWineD3DDeviceImpl_UpdateTexture,
7778 IWineD3DDeviceImpl_UpdateSurface,
7779 IWineD3DDeviceImpl_GetFrontBufferData,
7780 /*** object tracking ***/
7781 IWineD3DDeviceImpl_ResourceReleased,
7782 IWineD3DDeviceImpl_EnumResources
7785 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7787 /*** IUnknown methods ***/
7788 IWineD3DDeviceImpl_QueryInterface,
7789 IWineD3DDeviceImpl_AddRef,
7790 IWineD3DDeviceImpl_Release,
7791 /*** IWineD3DDevice methods ***/
7792 IWineD3DDeviceImpl_GetParent,
7793 /*** Creation methods**/
7794 IWineD3DDeviceImpl_CreateVertexBuffer,
7795 IWineD3DDeviceImpl_CreateIndexBuffer,
7796 IWineD3DDeviceImpl_CreateStateBlock,
7797 IWineD3DDeviceImpl_CreateSurface,
7798 IWineD3DDeviceImpl_CreateTexture,
7799 IWineD3DDeviceImpl_CreateVolumeTexture,
7800 IWineD3DDeviceImpl_CreateVolume,
7801 IWineD3DDeviceImpl_CreateCubeTexture,
7802 IWineD3DDeviceImpl_CreateQuery,
7803 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7804 IWineD3DDeviceImpl_CreateVertexDeclaration,
7805 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7806 IWineD3DDeviceImpl_CreateVertexShader,
7807 IWineD3DDeviceImpl_CreatePixelShader,
7808 IWineD3DDeviceImpl_CreatePalette,
7809 /*** Odd functions **/
7810 IWineD3DDeviceImpl_Init3D,
7811 IWineD3DDeviceImpl_InitGDI,
7812 IWineD3DDeviceImpl_Uninit3D,
7813 IWineD3DDeviceImpl_UninitGDI,
7814 IWineD3DDeviceImpl_SetMultithreaded,
7815 IWineD3DDeviceImpl_EvictManagedResources,
7816 IWineD3DDeviceImpl_GetAvailableTextureMem,
7817 IWineD3DDeviceImpl_GetBackBuffer,
7818 IWineD3DDeviceImpl_GetCreationParameters,
7819 IWineD3DDeviceImpl_GetDeviceCaps,
7820 IWineD3DDeviceImpl_GetDirect3D,
7821 IWineD3DDeviceImpl_GetDisplayMode,
7822 IWineD3DDeviceImpl_SetDisplayMode,
7823 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7824 IWineD3DDeviceImpl_GetRasterStatus,
7825 IWineD3DDeviceImpl_GetSwapChain,
7826 IWineD3DDeviceImpl_Reset,
7827 IWineD3DDeviceImpl_SetDialogBoxMode,
7828 IWineD3DDeviceImpl_SetCursorProperties,
7829 IWineD3DDeviceImpl_SetCursorPosition,
7830 IWineD3DDeviceImpl_ShowCursor,
7831 IWineD3DDeviceImpl_TestCooperativeLevel,
7832 /*** Getters and setters **/
7833 IWineD3DDeviceImpl_SetClipPlane,
7834 IWineD3DDeviceImpl_GetClipPlane,
7835 IWineD3DDeviceImpl_SetClipStatus,
7836 IWineD3DDeviceImpl_GetClipStatus,
7837 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7838 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7839 IWineD3DDeviceImpl_SetDepthStencilSurface,
7840 IWineD3DDeviceImpl_GetDepthStencilSurface,
7841 IWineD3DDeviceImpl_SetFVF,
7842 IWineD3DDeviceImpl_GetFVF,
7843 IWineD3DDeviceImpl_SetGammaRamp,
7844 IWineD3DDeviceImpl_GetGammaRamp,
7845 IWineD3DDeviceImpl_SetIndices,
7846 IWineD3DDeviceImpl_GetIndices,
7847 IWineD3DDeviceImpl_SetBaseVertexIndex,
7848 IWineD3DDeviceImpl_GetBaseVertexIndex,
7849 IWineD3DDeviceImpl_SetLight,
7850 IWineD3DDeviceImpl_GetLight,
7851 IWineD3DDeviceImpl_SetLightEnable,
7852 IWineD3DDeviceImpl_GetLightEnable,
7853 IWineD3DDeviceImpl_SetMaterial,
7854 IWineD3DDeviceImpl_GetMaterial,
7855 IWineD3DDeviceImpl_SetNPatchMode,
7856 IWineD3DDeviceImpl_GetNPatchMode,
7857 IWineD3DDeviceImpl_SetPaletteEntries,
7858 IWineD3DDeviceImpl_GetPaletteEntries,
7859 IWineD3DDeviceImpl_SetPixelShader,
7860 IWineD3DDeviceImpl_GetPixelShader,
7861 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7862 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7863 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7864 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7865 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7866 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7867 IWineD3DDeviceImpl_SetRenderState,
7868 IWineD3DDeviceImpl_GetRenderState,
7869 IWineD3DDeviceImpl_SetRenderTarget,
7870 IWineD3DDeviceImpl_GetRenderTarget,
7871 IWineD3DDeviceImpl_SetFrontBackBuffers,
7872 IWineD3DDeviceImpl_SetSamplerState,
7873 IWineD3DDeviceImpl_GetSamplerState,
7874 IWineD3DDeviceImpl_SetScissorRect,
7875 IWineD3DDeviceImpl_GetScissorRect,
7876 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7877 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7878 IWineD3DDeviceImpl_SetStreamSource,
7879 IWineD3DDeviceImpl_GetStreamSource,
7880 IWineD3DDeviceImpl_SetStreamSourceFreq,
7881 IWineD3DDeviceImpl_GetStreamSourceFreq,
7882 IWineD3DDeviceImpl_SetTexture,
7883 IWineD3DDeviceImpl_GetTexture,
7884 IWineD3DDeviceImpl_SetTextureStageState,
7885 IWineD3DDeviceImpl_GetTextureStageState,
7886 IWineD3DDeviceImpl_SetTransform,
7887 IWineD3DDeviceImpl_GetTransform,
7888 IWineD3DDeviceImpl_SetVertexDeclaration,
7889 IWineD3DDeviceImpl_GetVertexDeclaration,
7890 IWineD3DDeviceImpl_SetVertexShader,
7891 IWineD3DDeviceImpl_GetVertexShader,
7892 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7893 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7894 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7895 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7896 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7897 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7898 IWineD3DDeviceImpl_SetViewport,
7899 IWineD3DDeviceImpl_GetViewport,
7900 IWineD3DDeviceImpl_MultiplyTransform,
7901 IWineD3DDeviceImpl_ValidateDevice,
7902 IWineD3DDeviceImpl_ProcessVertices,
7903 /*** State block ***/
7904 IWineD3DDeviceImpl_BeginStateBlock,
7905 IWineD3DDeviceImpl_EndStateBlock,
7906 /*** Scene management ***/
7907 IWineD3DDeviceImpl_BeginScene,
7908 IWineD3DDeviceImpl_EndScene,
7909 IWineD3DDeviceImpl_Present,
7910 IWineD3DDeviceImpl_Clear,
7912 IWineD3DDeviceImpl_DrawPrimitive,
7913 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7914 IWineD3DDeviceImpl_DrawPrimitiveUP,
7915 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7916 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7917 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7918 IWineD3DDeviceImpl_DrawRectPatch,
7919 IWineD3DDeviceImpl_DrawTriPatch,
7920 IWineD3DDeviceImpl_DeletePatch,
7921 IWineD3DDeviceImpl_ColorFill,
7922 IWineD3DDeviceImpl_UpdateTexture,
7923 IWineD3DDeviceImpl_UpdateSurface,
7924 IWineD3DDeviceImpl_GetFrontBufferData,
7925 /*** object tracking ***/
7926 IWineD3DDeviceImpl_ResourceReleased,
7927 IWineD3DDeviceImpl_EnumResources
7930 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7931 WINED3DRS_ALPHABLENDENABLE ,
7932 WINED3DRS_ALPHAFUNC ,
7933 WINED3DRS_ALPHAREF ,
7934 WINED3DRS_ALPHATESTENABLE ,
7936 WINED3DRS_COLORWRITEENABLE ,
7937 WINED3DRS_DESTBLEND ,
7938 WINED3DRS_DITHERENABLE ,
7939 WINED3DRS_FILLMODE ,
7940 WINED3DRS_FOGDENSITY ,
7942 WINED3DRS_FOGSTART ,
7943 WINED3DRS_LASTPIXEL ,
7944 WINED3DRS_SHADEMODE ,
7945 WINED3DRS_SRCBLEND ,
7946 WINED3DRS_STENCILENABLE ,
7947 WINED3DRS_STENCILFAIL ,
7948 WINED3DRS_STENCILFUNC ,
7949 WINED3DRS_STENCILMASK ,
7950 WINED3DRS_STENCILPASS ,
7951 WINED3DRS_STENCILREF ,
7952 WINED3DRS_STENCILWRITEMASK ,
7953 WINED3DRS_STENCILZFAIL ,
7954 WINED3DRS_TEXTUREFACTOR ,
7965 WINED3DRS_ZWRITEENABLE
7968 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7969 WINED3DTSS_ADDRESSW ,
7970 WINED3DTSS_ALPHAARG0 ,
7971 WINED3DTSS_ALPHAARG1 ,
7972 WINED3DTSS_ALPHAARG2 ,
7973 WINED3DTSS_ALPHAOP ,
7974 WINED3DTSS_BUMPENVLOFFSET ,
7975 WINED3DTSS_BUMPENVLSCALE ,
7976 WINED3DTSS_BUMPENVMAT00 ,
7977 WINED3DTSS_BUMPENVMAT01 ,
7978 WINED3DTSS_BUMPENVMAT10 ,
7979 WINED3DTSS_BUMPENVMAT11 ,
7980 WINED3DTSS_COLORARG0 ,
7981 WINED3DTSS_COLORARG1 ,
7982 WINED3DTSS_COLORARG2 ,
7983 WINED3DTSS_COLOROP ,
7984 WINED3DTSS_RESULTARG ,
7985 WINED3DTSS_TEXCOORDINDEX ,
7986 WINED3DTSS_TEXTURETRANSFORMFLAGS
7989 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7990 WINED3DSAMP_ADDRESSU ,
7991 WINED3DSAMP_ADDRESSV ,
7992 WINED3DSAMP_ADDRESSW ,
7993 WINED3DSAMP_BORDERCOLOR ,
7994 WINED3DSAMP_MAGFILTER ,
7995 WINED3DSAMP_MINFILTER ,
7996 WINED3DSAMP_MIPFILTER ,
7997 WINED3DSAMP_MIPMAPLODBIAS ,
7998 WINED3DSAMP_MAXMIPLEVEL ,
7999 WINED3DSAMP_MAXANISOTROPY ,
8000 WINED3DSAMP_SRGBTEXTURE ,
8001 WINED3DSAMP_ELEMENTINDEX
8004 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8006 WINED3DRS_AMBIENTMATERIALSOURCE ,
8007 WINED3DRS_CLIPPING ,
8008 WINED3DRS_CLIPPLANEENABLE ,
8009 WINED3DRS_COLORVERTEX ,
8010 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8011 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8012 WINED3DRS_FOGDENSITY ,
8014 WINED3DRS_FOGSTART ,
8015 WINED3DRS_FOGTABLEMODE ,
8016 WINED3DRS_FOGVERTEXMODE ,
8017 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8018 WINED3DRS_LIGHTING ,
8019 WINED3DRS_LOCALVIEWER ,
8020 WINED3DRS_MULTISAMPLEANTIALIAS ,
8021 WINED3DRS_MULTISAMPLEMASK ,
8022 WINED3DRS_NORMALIZENORMALS ,
8023 WINED3DRS_PATCHEDGESTYLE ,
8024 WINED3DRS_POINTSCALE_A ,
8025 WINED3DRS_POINTSCALE_B ,
8026 WINED3DRS_POINTSCALE_C ,
8027 WINED3DRS_POINTSCALEENABLE ,
8028 WINED3DRS_POINTSIZE ,
8029 WINED3DRS_POINTSIZE_MAX ,
8030 WINED3DRS_POINTSIZE_MIN ,
8031 WINED3DRS_POINTSPRITEENABLE ,
8032 WINED3DRS_RANGEFOGENABLE ,
8033 WINED3DRS_SPECULARMATERIALSOURCE ,
8034 WINED3DRS_TWEENFACTOR ,
8035 WINED3DRS_VERTEXBLEND ,
8036 WINED3DRS_CULLMODE ,
8040 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8041 WINED3DTSS_TEXCOORDINDEX ,
8042 WINED3DTSS_TEXTURETRANSFORMFLAGS
8045 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8046 WINED3DSAMP_DMAPOFFSET
8049 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8050 DWORD rep = This->StateTable[state].representative;
8054 WineD3DContext *context;
8057 for(i = 0; i < This->numContexts; i++) {
8058 context = This->contexts[i];
8059 if(isStateDirty(context, rep)) continue;
8061 context->dirtyArray[context->numDirtyEntries++] = rep;
8064 context->isStateDirty[idx] |= (1 << shift);
8068 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8069 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8070 /* The drawable size of a pbuffer render target is the current pbuffer size
8072 *width = dev->pbufferWidth;
8073 *height = dev->pbufferHeight;
8076 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8077 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8079 *width = This->pow2Width;
8080 *height = This->pow2Height;
8083 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8084 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8085 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8086 * current context's drawable, which is the size of the back buffer of the swapchain
8087 * the active context belongs to. The back buffer of the swapchain is stored as the
8088 * surface the context belongs to.
8090 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8091 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;