wined3d: Check real depth/stencil capabilities based on WGL pixel formats.
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob952e796e20dce87a295f4ac65e76357399e759f7
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
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 */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
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; \
66 object->ref = 1; \
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); \
99 *pp##type = NULL; \
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); \
108 *pp##type = NULL; \
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);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
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);
156 return refCount;
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);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
207 return WINED3D_OK;
210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
211 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
212 IUnknown *parent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 IWineD3DVertexBufferImpl *object;
215 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
216 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
217 BOOL conv;
219 if(Size == 0) {
220 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
221 *ppVertexBuffer = NULL;
222 return WINED3DERR_INVALIDCALL;
223 } else if(Pool == WINED3DPOOL_SCRATCH) {
224 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
225 * anyway, SCRATCH vertex buffers aren't useable anywhere
227 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
228 *ppVertexBuffer = NULL;
229 return WINED3DERR_INVALIDCALL;
232 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
234 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);
235 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
237 object->fvf = FVF;
239 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
240 * drawStridedFast (half-life 2).
242 * Basically converting the vertices in the buffer is quite expensive, and observations
243 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
244 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
246 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
247 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
248 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
249 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
250 * dx7 apps.
251 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
252 * more. In this call we can convert dx7 buffers too.
254 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
255 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
256 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
257 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
258 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
259 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
260 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
261 } else if(dxVersion <= 7 && conv) {
262 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
263 } else {
264 object->Flags |= VBFLAG_CREATEVBO;
266 return WINED3D_OK;
269 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
270 GLenum error, glUsage;
271 TRACE("Creating VBO for Index Buffer %p\n", object);
273 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
274 * restored on the next draw
276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
278 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
279 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
280 ENTER_GL();
282 while(glGetError());
284 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR || object->vbo == 0) {
287 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
288 goto out;
291 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
295 goto out;
298 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
299 * copy no readback will be needed
301 glUsage = GL_STATIC_DRAW_ARB;
302 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
303 error = glGetError();
304 if(error != GL_NO_ERROR) {
305 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
306 goto out;
308 LEAVE_GL();
309 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
310 return;
312 out:
313 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
314 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
315 LEAVE_GL();
316 object->vbo = 0;
319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
320 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
321 HANDLE *sharedHandle, IUnknown *parent) {
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DIndexBufferImpl *object;
324 TRACE("(%p) Creating index buffer\n", This);
326 /* Allocate the storage for the device */
327 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
329 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
330 CreateIndexBufferVBO(This, object);
333 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
334 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
335 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
337 return WINED3D_OK;
340 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
343 IWineD3DStateBlockImpl *object;
344 int i, j;
345 HRESULT temp_result;
347 D3DCREATEOBJECTINSTANCE(object, StateBlock)
348 object->blockType = Type;
350 for(i = 0; i < LIGHTMAP_SIZE; i++) {
351 list_init(&object->lightMap[i]);
354 /* Special case - Used during initialization to produce a placeholder stateblock
355 so other functions called can update a state block */
356 if (Type == WINED3DSBT_INIT) {
357 /* Don't bother increasing the reference count otherwise a device will never
358 be freed due to circular dependencies */
359 return WINED3D_OK;
362 temp_result = allocate_shader_constants(object);
363 if (WINED3D_OK != temp_result)
364 return temp_result;
366 /* Otherwise, might as well set the whole state block to the appropriate values */
367 if (This->stateBlock != NULL)
368 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
369 else
370 memset(object->streamFreq, 1, sizeof(object->streamFreq));
372 /* Reset the ref and type after kludging it */
373 object->wineD3DDevice = This;
374 object->ref = 1;
375 object->blockType = Type;
377 TRACE("Updating changed flags appropriate for type %d\n", Type);
379 if (Type == WINED3DSBT_ALL) {
381 TRACE("ALL => Pretend everything has changed\n");
382 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
384 /* Lights are not part of the changed / set structure */
385 for(j = 0; j < LIGHTMAP_SIZE; j++) {
386 struct list *e;
387 LIST_FOR_EACH(e, &object->lightMap[j]) {
388 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
389 light->changed = TRUE;
390 light->enabledChanged = TRUE;
393 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
394 object->contained_render_states[j - 1] = j;
396 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
397 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
398 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
399 object->contained_transform_states[j - 1] = j;
401 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
402 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
403 object->contained_vs_consts_f[j] = j;
405 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_vs_consts_i[j] = j;
409 object->num_contained_vs_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_vs_consts_b[j] = j;
413 object->num_contained_vs_consts_b = MAX_CONST_B;
414 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
415 object->contained_ps_consts_f[j] = j;
417 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
418 for(j = 0; j < MAX_CONST_I; j++) {
419 object->contained_ps_consts_i[j] = j;
421 object->num_contained_ps_consts_i = MAX_CONST_I;
422 for(j = 0; j < MAX_CONST_B; j++) {
423 object->contained_ps_consts_b[j] = j;
425 object->num_contained_ps_consts_b = MAX_CONST_B;
426 for(i = 0; i < MAX_TEXTURES; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
428 object->contained_tss_states[object->num_contained_tss_states].stage = i;
429 object->contained_tss_states[object->num_contained_tss_states].state = j;
430 object->num_contained_tss_states++;
433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
434 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
435 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
436 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
437 object->num_contained_sampler_states++;
441 for(i = 0; i < MAX_STREAMS; i++) {
442 if(object->streamSource[i]) {
443 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
446 if(object->pIndexData) {
447 IWineD3DIndexBuffer_AddRef(object->pIndexData);
449 if(object->vertexShader) {
450 IWineD3DVertexShader_AddRef(object->vertexShader);
452 if(object->pixelShader) {
453 IWineD3DPixelShader_AddRef(object->pixelShader);
456 } else if (Type == WINED3DSBT_PIXELSTATE) {
458 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
461 object->changed.pixelShader = TRUE;
463 /* Pixel Shader Constants */
464 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
465 object->contained_ps_consts_f[i] = i;
466 object->changed.pixelShaderConstantsF[i] = TRUE;
468 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
469 for (i = 0; i < MAX_CONST_B; ++i) {
470 object->contained_ps_consts_b[i] = i;
471 object->changed.pixelShaderConstantsB[i] = TRUE;
473 object->num_contained_ps_consts_b = MAX_CONST_B;
474 for (i = 0; i < MAX_CONST_I; ++i) {
475 object->contained_ps_consts_i[i] = i;
476 object->changed.pixelShaderConstantsI[i] = TRUE;
478 object->num_contained_ps_consts_i = MAX_CONST_I;
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
481 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
482 object->contained_render_states[i] = SavedPixelStates_R[i];
484 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
485 for (j = 0; j < MAX_TEXTURES; j++) {
486 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
487 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
488 object->contained_tss_states[object->num_contained_tss_states].stage = j;
489 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
490 object->num_contained_tss_states++;
493 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
494 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
496 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
497 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
498 object->num_contained_sampler_states++;
501 if(object->pixelShader) {
502 IWineD3DPixelShader_AddRef(object->pixelShader);
505 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
506 * on them. This makes releasing the buffer easier
508 for(i = 0; i < MAX_STREAMS; i++) {
509 object->streamSource[i] = NULL;
511 object->pIndexData = NULL;
512 object->vertexShader = NULL;
514 } else if (Type == WINED3DSBT_VERTEXSTATE) {
516 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
517 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
519 object->changed.vertexShader = TRUE;
521 /* Vertex Shader Constants */
522 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
523 object->changed.vertexShaderConstantsF[i] = TRUE;
524 object->contained_vs_consts_f[i] = i;
526 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
527 for (i = 0; i < MAX_CONST_B; ++i) {
528 object->changed.vertexShaderConstantsB[i] = TRUE;
529 object->contained_vs_consts_b[i] = i;
531 object->num_contained_vs_consts_b = MAX_CONST_B;
532 for (i = 0; i < MAX_CONST_I; ++i) {
533 object->changed.vertexShaderConstantsI[i] = TRUE;
534 object->contained_vs_consts_i[i] = i;
536 object->num_contained_vs_consts_i = MAX_CONST_I;
537 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
538 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
539 object->contained_render_states[i] = SavedVertexStates_R[i];
541 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
542 for (j = 0; j < MAX_TEXTURES; j++) {
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
544 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
545 object->contained_tss_states[object->num_contained_tss_states].stage = j;
546 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
547 object->num_contained_tss_states++;
550 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
551 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
552 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
555 object->num_contained_sampler_states++;
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
560 struct list *e;
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
568 for(i = 0; i < MAX_STREAMS; i++) {
569 if(object->streamSource[i]) {
570 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
573 if(object->vertexShader) {
574 IWineD3DVertexShader_AddRef(object->vertexShader);
576 object->pIndexData = NULL;
577 object->pixelShader = NULL;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int Size = 1;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
602 TRACE("(%p) Create surface\n",This);
604 /** FIXME: Check ranges on the inputs are valid
605 * MSDN
606 * MultisampleQuality
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
611 * must all match.
612 *******************************/
616 * TODO: Discard MSDN
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
631 /** FIXME: Check that the format is supported
632 * by the device.
633 *******************************/
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
637 * space!
638 *********************************/
639 if (WINED3DFMT_UNKNOWN == Format) {
640 Size = 0;
641 } else if (Format == WINED3DFMT_DXT1) {
642 /* DXT1 is half byte per pixel */
643 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
645 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
646 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
648 } else {
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
651 Size *= Height;
654 /** Create and initialise the surface resource **/
655 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
656 /* "Standalone" surface */
657 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
659 object->currentDesc.Width = Width;
660 object->currentDesc.Height = Height;
661 object->currentDesc.MultiSampleType = MultiSample;
662 object->currentDesc.MultiSampleQuality = MultisampleQuality;
663 object->glDescription.level = Level;
665 /* Flags */
666 object->Flags = 0;
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
726 switch(Impl) {
727 case SURFACE_OPENGL:
728 /* Check if a 3D adapter is available when creating gl surfaces */
729 if(!This->adapter) {
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
735 break;
737 case SURFACE_GDI:
738 object->lpVtbl = &IWineGDISurface_Vtbl;
739 break;
741 default:
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
762 unsigned int i;
763 UINT tmpW;
764 UINT tmpH;
765 HRESULT hr;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
772 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
773 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
774 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
776 /* TODO: It should only be possible to create textures for formats
777 that are reported as supported */
778 if (WINED3DFMT_UNKNOWN >= Format) {
779 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
780 return WINED3DERR_INVALIDCALL;
783 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
784 D3DINITIALIZEBASETEXTURE(object->baseTexture);
785 object->width = Width;
786 object->height = Height;
788 /** Non-power2 support **/
789 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
790 pow2Width = Width;
791 pow2Height = Height;
792 } else {
793 /* Find the nearest pow2 match */
794 pow2Width = pow2Height = 1;
795 while (pow2Width < Width) pow2Width <<= 1;
796 while (pow2Height < Height) pow2Height <<= 1;
798 if(pow2Width != Width || pow2Height != Height) {
799 if(Levels > 1) {
800 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
801 HeapFree(GetProcessHeap(), 0, object);
802 *ppTexture = NULL;
803 return WINED3DERR_INVALIDCALL;
804 } else {
805 Levels = 1;
810 /** FIXME: add support for real non-power-two if it's provided by the video card **/
811 /* Precalculated scaling for 'faked' non power of two texture coords.
812 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
813 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
814 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
816 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
817 (Width != pow2Width || Height != pow2Height) &&
818 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
820 object->baseTexture.pow2Matrix[0] = (float)Width;
821 object->baseTexture.pow2Matrix[5] = (float)Height;
822 object->baseTexture.pow2Matrix[10] = 1.0;
823 object->baseTexture.pow2Matrix[15] = 1.0;
824 object->target = GL_TEXTURE_RECTANGLE_ARB;
825 } else {
826 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
827 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
828 object->baseTexture.pow2Matrix[10] = 1.0;
829 object->baseTexture.pow2Matrix[15] = 1.0;
830 object->target = GL_TEXTURE_2D;
832 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
834 /* Calculate levels for mip mapping */
835 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
836 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
837 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
838 return WINED3DERR_INVALIDCALL;
840 if(Levels > 1) {
841 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
842 return WINED3DERR_INVALIDCALL;
844 object->baseTexture.levels = 1;
845 } else if (Levels == 0) {
846 TRACE("calculating levels %d\n", object->baseTexture.levels);
847 object->baseTexture.levels++;
848 tmpW = Width;
849 tmpH = Height;
850 while (tmpW > 1 || tmpH > 1) {
851 tmpW = max(1, tmpW >> 1);
852 tmpH = max(1, tmpH >> 1);
853 object->baseTexture.levels++;
855 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
858 /* Generate all the surfaces */
859 tmpW = Width;
860 tmpH = Height;
861 for (i = 0; i < object->baseTexture.levels; i++)
863 /* use the callback to create the texture surface */
864 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
865 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
866 FIXME("Failed to create surface %p\n", object);
867 /* clean up */
868 object->surfaces[i] = NULL;
869 IWineD3DTexture_Release((IWineD3DTexture *)object);
871 *ppTexture = NULL;
872 return hr;
875 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
876 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
877 /* calculate the next mipmap level */
878 tmpW = max(1, tmpW >> 1);
879 tmpH = max(1, tmpH >> 1);
881 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
883 TRACE("(%p) : Created texture %p\n", This, object);
884 return WINED3D_OK;
887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
888 UINT Width, UINT Height, UINT Depth,
889 UINT Levels, DWORD Usage,
890 WINED3DFORMAT Format, WINED3DPOOL Pool,
891 IWineD3DVolumeTexture **ppVolumeTexture,
892 HANDLE *pSharedHandle, IUnknown *parent,
893 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
896 IWineD3DVolumeTextureImpl *object;
897 unsigned int i;
898 UINT tmpW;
899 UINT tmpH;
900 UINT tmpD;
901 const GlPixelFormatDesc *glDesc;
903 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
905 /* TODO: It should only be possible to create textures for formats
906 that are reported as supported */
907 if (WINED3DFMT_UNKNOWN >= Format) {
908 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
909 return WINED3DERR_INVALIDCALL;
911 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
912 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
913 return WINED3DERR_INVALIDCALL;
916 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
917 D3DINITIALIZEBASETEXTURE(object->baseTexture);
919 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
920 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
922 object->width = Width;
923 object->height = Height;
924 object->depth = Depth;
926 /* Is NP2 support for volumes needed? */
927 object->baseTexture.pow2Matrix[ 0] = 1.0;
928 object->baseTexture.pow2Matrix[ 5] = 1.0;
929 object->baseTexture.pow2Matrix[10] = 1.0;
930 object->baseTexture.pow2Matrix[15] = 1.0;
932 /* Calculate levels for mip mapping */
933 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
934 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
935 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
936 return WINED3DERR_INVALIDCALL;
938 if(Levels > 1) {
939 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
940 return WINED3DERR_INVALIDCALL;
942 Levels = 1;
943 } else if (Levels == 0) {
944 object->baseTexture.levels++;
945 tmpW = Width;
946 tmpH = Height;
947 tmpD = Depth;
948 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
949 tmpW = max(1, tmpW >> 1);
950 tmpH = max(1, tmpH >> 1);
951 tmpD = max(1, tmpD >> 1);
952 object->baseTexture.levels++;
954 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
957 /* Generate all the surfaces */
958 tmpW = Width;
959 tmpH = Height;
960 tmpD = Depth;
962 for (i = 0; i < object->baseTexture.levels; i++)
964 HRESULT hr;
965 /* Create the volume */
966 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
967 &object->volumes[i], pSharedHandle);
969 if(FAILED(hr)) {
970 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
971 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
972 *ppVolumeTexture = NULL;
973 return hr;
976 /* Set its container to this object */
977 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
979 /* calculate the next mipmap level */
980 tmpW = max(1, tmpW >> 1);
981 tmpH = max(1, tmpH >> 1);
982 tmpD = max(1, tmpD >> 1);
984 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
986 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
987 TRACE("(%p) : Created volume texture %p\n", This, object);
988 return WINED3D_OK;
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
992 UINT Width, UINT Height, UINT Depth,
993 DWORD Usage,
994 WINED3DFORMAT Format, WINED3DPOOL Pool,
995 IWineD3DVolume** ppVolume,
996 HANDLE* pSharedHandle, IUnknown *parent) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1000 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1002 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1003 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1004 return WINED3DERR_INVALIDCALL;
1007 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1009 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1010 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.Depth = Depth;
1015 object->bytesPerPixel = formatDesc->bpp;
1017 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1018 object->lockable = TRUE;
1019 object->locked = FALSE;
1020 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1021 object->dirty = TRUE;
1023 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1027 UINT Levels, DWORD Usage,
1028 WINED3DFORMAT Format, WINED3DPOOL Pool,
1029 IWineD3DCubeTexture **ppCubeTexture,
1030 HANDLE *pSharedHandle, IUnknown *parent,
1031 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1035 unsigned int i, j;
1036 UINT tmpW;
1037 HRESULT hr;
1038 unsigned int pow2EdgeLength = EdgeLength;
1039 const GlPixelFormatDesc *glDesc;
1040 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1042 /* TODO: It should only be possible to create textures for formats
1043 that are reported as supported */
1044 if (WINED3DFMT_UNKNOWN >= Format) {
1045 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1046 return WINED3DERR_INVALIDCALL;
1049 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1050 WARN("(%p) : Tried to create not supported cube texture\n", This);
1051 return WINED3DERR_INVALIDCALL;
1054 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1055 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1057 TRACE("(%p) Create Cube Texture\n", This);
1059 /** Non-power2 support **/
1061 /* Find the nearest pow2 match */
1062 pow2EdgeLength = 1;
1063 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1065 object->edgeLength = EdgeLength;
1066 /* TODO: support for native non-power 2 */
1067 /* Precalculated scaling for 'faked' non power of two texture coords */
1068 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1069 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1070 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[15] = 1.0;
1073 /* Calculate levels for mip mapping */
1074 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1075 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1076 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1077 HeapFree(GetProcessHeap(), 0, object);
1078 *ppCubeTexture = NULL;
1080 return WINED3DERR_INVALIDCALL;
1082 if(Levels > 1) {
1083 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1084 HeapFree(GetProcessHeap(), 0, object);
1085 *ppCubeTexture = NULL;
1087 return WINED3DERR_INVALIDCALL;
1089 Levels = 1;
1090 } else if (Levels == 0) {
1091 object->baseTexture.levels++;
1092 tmpW = EdgeLength;
1093 while (tmpW > 1) {
1094 tmpW = max(1, tmpW >> 1);
1095 object->baseTexture.levels++;
1097 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1100 /* Generate all the surfaces */
1101 tmpW = EdgeLength;
1102 for (i = 0; i < object->baseTexture.levels; i++) {
1104 /* Create the 6 faces */
1105 for (j = 0; j < 6; j++) {
1107 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1108 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1110 if(hr!= WINED3D_OK) {
1111 /* clean up */
1112 int k;
1113 int l;
1114 for (l = 0; l < j; l++) {
1115 IWineD3DSurface_Release(object->surfaces[l][i]);
1117 for (k = 0; k < i; k++) {
1118 for (l = 0; l < 6; l++) {
1119 IWineD3DSurface_Release(object->surfaces[l][k]);
1123 FIXME("(%p) Failed to create surface\n",object);
1124 HeapFree(GetProcessHeap(),0,object);
1125 *ppCubeTexture = NULL;
1126 return hr;
1128 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1129 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1131 tmpW = max(1, tmpW >> 1);
1133 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1135 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1136 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1137 return WINED3D_OK;
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1142 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1143 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1145 /* Just a check to see if we support this type of query */
1146 switch(Type) {
1147 case WINED3DQUERYTYPE_OCCLUSION:
1148 TRACE("(%p) occlusion query\n", This);
1149 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1150 hr = WINED3D_OK;
1151 else
1152 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1153 break;
1155 case WINED3DQUERYTYPE_EVENT:
1156 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1157 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1158 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1160 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1162 hr = WINED3D_OK;
1163 break;
1165 case WINED3DQUERYTYPE_VCACHE:
1166 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1167 case WINED3DQUERYTYPE_VERTEXSTATS:
1168 case WINED3DQUERYTYPE_TIMESTAMP:
1169 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1170 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1171 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1172 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1173 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1174 case WINED3DQUERYTYPE_PIXELTIMINGS:
1175 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1176 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1177 default:
1178 FIXME("(%p) Unhandled query type %d\n", This, Type);
1180 if(NULL == ppQuery || hr != WINED3D_OK) {
1181 return hr;
1184 D3DCREATEOBJECTINSTANCE(object, Query)
1185 object->type = Type;
1186 object->state = QUERY_CREATED;
1187 /* allocated the 'extended' data based on the type of query requested */
1188 switch(Type){
1189 case WINED3DQUERYTYPE_OCCLUSION:
1190 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1191 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1193 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1194 TRACE("(%p) Allocating data for an occlusion query\n", This);
1195 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1196 break;
1198 case WINED3DQUERYTYPE_EVENT:
1199 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1200 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1202 if(GL_SUPPORT(APPLE_FENCE)) {
1203 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1204 checkGLcall("glGenFencesAPPLE");
1205 } else if(GL_SUPPORT(NV_FENCE)) {
1206 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1207 checkGLcall("glGenFencesNV");
1209 break;
1211 case WINED3DQUERYTYPE_VCACHE:
1212 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1213 case WINED3DQUERYTYPE_VERTEXSTATS:
1214 case WINED3DQUERYTYPE_TIMESTAMP:
1215 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1216 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1217 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1218 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1219 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1220 case WINED3DQUERYTYPE_PIXELTIMINGS:
1221 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1222 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1223 default:
1224 object->extendedData = 0;
1225 FIXME("(%p) Unhandled query type %d\n",This , Type);
1227 TRACE("(%p) : Created Query %p\n", This, object);
1228 return WINED3D_OK;
1231 /*****************************************************************************
1232 * IWineD3DDeviceImpl_SetupFullscreenWindow
1234 * Helper function that modifies a HWND's Style and ExStyle for proper
1235 * fullscreen use.
1237 * Params:
1238 * iface: Pointer to the IWineD3DDevice interface
1239 * window: Window to setup
1241 *****************************************************************************/
1242 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 LONG style, exStyle;
1246 /* Don't do anything if an original style is stored.
1247 * That shouldn't happen
1249 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1250 if (This->style || This->exStyle) {
1251 ERR("(%p): Want to change the window parameters of HWND %p, but "
1252 "another style is stored for restoration afterwards\n", This, window);
1255 /* Get the parameters and save them */
1256 style = GetWindowLongW(window, GWL_STYLE);
1257 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1258 This->style = style;
1259 This->exStyle = exStyle;
1261 /* Filter out window decorations */
1262 style &= ~WS_CAPTION;
1263 style &= ~WS_THICKFRAME;
1264 exStyle &= ~WS_EX_WINDOWEDGE;
1265 exStyle &= ~WS_EX_CLIENTEDGE;
1267 /* Make sure the window is managed, otherwise we won't get keyboard input */
1268 style |= WS_POPUP | WS_SYSMENU;
1270 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1271 This->style, This->exStyle, style, exStyle);
1273 SetWindowLongW(window, GWL_STYLE, style);
1274 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1276 /* Inform the window about the update. */
1277 SetWindowPos(window, HWND_TOP, 0, 0,
1278 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1279 ShowWindow(window, SW_NORMAL);
1282 /*****************************************************************************
1283 * IWineD3DDeviceImpl_RestoreWindow
1285 * Helper function that restores a windows' properties when taking it out
1286 * of fullscreen mode
1288 * Params:
1289 * iface: Pointer to the IWineD3DDevice interface
1290 * window: Window to setup
1292 *****************************************************************************/
1293 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1297 * switch, do nothing
1299 if (!This->style && !This->exStyle) return;
1301 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1302 This, window, This->style, This->exStyle);
1304 SetWindowLongW(window, GWL_STYLE, This->style);
1305 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1307 /* Delete the old values */
1308 This->style = 0;
1309 This->exStyle = 0;
1311 /* Inform the window about the update */
1312 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1313 0, 0, 0, 0, /* Pos, Size, ignored */
1314 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1317 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1318 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1319 IUnknown* parent,
1320 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1321 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1324 HDC hDc;
1325 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1326 HRESULT hr = WINED3D_OK;
1327 IUnknown *bufferParent;
1328 BOOL displaymode_set = FALSE;
1329 WINED3DDISPLAYMODE Mode;
1330 const StaticPixelFormatDesc *formatDesc;
1332 TRACE("(%p) : Created Additional Swap Chain\n", This);
1334 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1335 * does a device hold a reference to a swap chain giving them a lifetime of the device
1336 * or does the swap chain notify the device of its destruction.
1337 *******************************/
1339 /* Check the params */
1340 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1341 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1342 return WINED3DERR_INVALIDCALL;
1343 } else if (pPresentationParameters->BackBufferCount > 1) {
1344 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");
1347 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1349 /*********************
1350 * Lookup the window Handle and the relating X window handle
1351 ********************/
1353 /* Setup hwnd we are using, plus which display this equates to */
1354 object->win_handle = pPresentationParameters->hDeviceWindow;
1355 if (!object->win_handle) {
1356 object->win_handle = This->createParms.hFocusWindow;
1358 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1360 hDc = GetDC(object->win_handle);
1361 TRACE("Using hDc %p\n", hDc);
1363 if (NULL == hDc) {
1364 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1365 return WINED3DERR_NOTAVAILABLE;
1368 /* Get info on the current display setup */
1369 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1370 object->orig_width = Mode.Width;
1371 object->orig_height = Mode.Height;
1372 object->orig_fmt = Mode.Format;
1373 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1375 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1376 * then the corresponding dimension of the client area of the hDeviceWindow
1377 * (or the focus window, if hDeviceWindow is NULL) is taken.
1378 **********************/
1380 if (pPresentationParameters->Windowed &&
1381 ((pPresentationParameters->BackBufferWidth == 0) ||
1382 (pPresentationParameters->BackBufferHeight == 0) ||
1383 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1385 RECT Rect;
1386 GetClientRect(object->win_handle, &Rect);
1388 if (pPresentationParameters->BackBufferWidth == 0) {
1389 pPresentationParameters->BackBufferWidth = Rect.right;
1390 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1392 if (pPresentationParameters->BackBufferHeight == 0) {
1393 pPresentationParameters->BackBufferHeight = Rect.bottom;
1394 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1396 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1397 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1398 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1402 /* Put the correct figures in the presentation parameters */
1403 TRACE("Copying across presentation parameters\n");
1404 object->presentParms = *pPresentationParameters;
1406 TRACE("calling rendertarget CB\n");
1407 hr = D3DCB_CreateRenderTarget(This->parent,
1408 parent,
1409 object->presentParms.BackBufferWidth,
1410 object->presentParms.BackBufferHeight,
1411 object->presentParms.BackBufferFormat,
1412 object->presentParms.MultiSampleType,
1413 object->presentParms.MultiSampleQuality,
1414 TRUE /* Lockable */,
1415 &object->frontBuffer,
1416 NULL /* pShared (always null)*/);
1417 if (object->frontBuffer != NULL) {
1418 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1419 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1420 } else {
1421 ERR("Failed to create the front buffer\n");
1422 goto error;
1425 /*********************
1426 * Windowed / Fullscreen
1427 *******************/
1430 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1431 * so we should really check to see if there is a fullscreen swapchain already
1432 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1433 **************************************/
1435 if (!pPresentationParameters->Windowed) {
1436 WINED3DDISPLAYMODE mode;
1439 /* Change the display settings */
1440 mode.Width = pPresentationParameters->BackBufferWidth;
1441 mode.Height = pPresentationParameters->BackBufferHeight;
1442 mode.Format = pPresentationParameters->BackBufferFormat;
1443 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1445 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1446 displaymode_set = TRUE;
1447 IWineD3DDevice_SetFullscreen(iface, TRUE);
1451 * Create an opengl context for the display visual
1452 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1453 * use different properties after that point in time. FIXME: How to handle when requested format
1454 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1455 * it chooses is identical to the one already being used!
1456 **********************************/
1457 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1459 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1460 if(!object->context)
1461 return E_OUTOFMEMORY;
1462 object->num_contexts = 1;
1464 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1465 if (!object->context[0]) {
1466 ERR("Failed to create a new context\n");
1467 hr = WINED3DERR_NOTAVAILABLE;
1468 goto error;
1469 } else {
1470 TRACE("Context created (HWND=%p, glContext=%p)\n",
1471 object->win_handle, object->context[0]->glCtx);
1474 /*********************
1475 * Create the back, front and stencil buffers
1476 *******************/
1477 if(object->presentParms.BackBufferCount > 0) {
1478 int i;
1480 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1481 if(!object->backBuffer) {
1482 ERR("Out of memory\n");
1483 hr = E_OUTOFMEMORY;
1484 goto error;
1487 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1488 TRACE("calling rendertarget CB\n");
1489 hr = D3DCB_CreateRenderTarget(This->parent,
1490 parent,
1491 object->presentParms.BackBufferWidth,
1492 object->presentParms.BackBufferHeight,
1493 object->presentParms.BackBufferFormat,
1494 object->presentParms.MultiSampleType,
1495 object->presentParms.MultiSampleQuality,
1496 TRUE /* Lockable */,
1497 &object->backBuffer[i],
1498 NULL /* pShared (always null)*/);
1499 if(hr == WINED3D_OK && object->backBuffer[i]) {
1500 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1501 } else {
1502 ERR("Cannot create new back buffer\n");
1503 goto error;
1505 ENTER_GL();
1506 glDrawBuffer(GL_BACK);
1507 checkGLcall("glDrawBuffer(GL_BACK)");
1508 LEAVE_GL();
1510 } else {
1511 object->backBuffer = NULL;
1513 /* Single buffering - draw to front buffer */
1514 ENTER_GL();
1515 glDrawBuffer(GL_FRONT);
1516 checkGLcall("glDrawBuffer(GL_FRONT)");
1517 LEAVE_GL();
1520 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1521 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1522 TRACE("Creating depth stencil buffer\n");
1523 if (This->auto_depth_stencil_buffer == NULL ) {
1524 hr = D3DCB_CreateDepthStencil(This->parent,
1525 parent,
1526 object->presentParms.BackBufferWidth,
1527 object->presentParms.BackBufferHeight,
1528 object->presentParms.AutoDepthStencilFormat,
1529 object->presentParms.MultiSampleType,
1530 object->presentParms.MultiSampleQuality,
1531 FALSE /* FIXME: Discard */,
1532 &This->auto_depth_stencil_buffer,
1533 NULL /* pShared (always null)*/ );
1534 if (This->auto_depth_stencil_buffer != NULL)
1535 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1538 /** TODO: A check on width, height and multisample types
1539 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1540 ****************************/
1541 object->wantsDepthStencilBuffer = TRUE;
1542 } else {
1543 object->wantsDepthStencilBuffer = FALSE;
1546 TRACE("Created swapchain %p\n", object);
1547 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1548 return WINED3D_OK;
1550 error:
1551 if (displaymode_set) {
1552 DEVMODEW devmode;
1553 RECT clip_rc;
1555 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1556 ClipCursor(NULL);
1558 /* Change the display settings */
1559 memset(&devmode, 0, sizeof(devmode));
1560 devmode.dmSize = sizeof(devmode);
1561 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1562 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1563 devmode.dmPelsWidth = object->orig_width;
1564 devmode.dmPelsHeight = object->orig_height;
1565 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1568 if (object->backBuffer) {
1569 int i;
1570 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1571 if(object->backBuffer[i]) {
1572 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1573 IUnknown_Release(bufferParent); /* once for the get parent */
1574 if (IUnknown_Release(bufferParent) > 0) {
1575 FIXME("(%p) Something's still holding the back buffer\n",This);
1579 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1580 object->backBuffer = NULL;
1582 if(object->context[0])
1583 DestroyContext(This, object->context[0]);
1584 if(object->frontBuffer) {
1585 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1586 IUnknown_Release(bufferParent); /* once for the get parent */
1587 if (IUnknown_Release(bufferParent) > 0) {
1588 FIXME("(%p) Something's still holding the front buffer\n",This);
1591 HeapFree(GetProcessHeap(), 0, object);
1592 return hr;
1595 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1596 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1598 TRACE("(%p)\n", This);
1600 return This->NumberOfSwapChains;
1603 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1605 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1607 if(iSwapChain < This->NumberOfSwapChains) {
1608 *pSwapChain = This->swapchains[iSwapChain];
1609 IWineD3DSwapChain_AddRef(*pSwapChain);
1610 TRACE("(%p) returning %p\n", This, *pSwapChain);
1611 return WINED3D_OK;
1612 } else {
1613 TRACE("Swapchain out of range\n");
1614 *pSwapChain = NULL;
1615 return WINED3DERR_INVALIDCALL;
1619 /*****
1620 * Vertex Declaration
1621 *****/
1622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1623 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1625 IWineD3DVertexDeclarationImpl *object = NULL;
1626 HRESULT hr = WINED3D_OK;
1628 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1629 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1631 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1633 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1634 if(FAILED(hr)) {
1635 *ppVertexDeclaration = NULL;
1636 HeapFree(GetProcessHeap(), 0, object);
1639 return hr;
1642 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1643 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1645 unsigned int idx, idx2;
1646 unsigned int offset;
1647 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1648 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1649 BOOL has_blend_idx = has_blend &&
1650 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1651 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1652 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1653 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1654 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1655 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1656 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1658 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1659 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1661 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1662 WINED3DVERTEXELEMENT *elements = NULL;
1664 unsigned int size;
1665 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1666 if (has_blend_idx) num_blends--;
1668 /* Compute declaration size */
1669 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1670 has_psize + has_diffuse + has_specular + num_textures + 1;
1672 /* convert the declaration */
1673 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1674 if (!elements)
1675 return 0;
1677 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1678 idx = 0;
1679 if (has_pos) {
1680 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1682 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1684 else {
1685 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1686 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1688 elements[idx].UsageIndex = 0;
1689 idx++;
1691 if (has_blend && (num_blends > 0)) {
1692 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1693 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1694 else
1695 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1696 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1697 elements[idx].UsageIndex = 0;
1698 idx++;
1700 if (has_blend_idx) {
1701 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1702 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1703 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1704 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1705 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1706 else
1707 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1708 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1709 elements[idx].UsageIndex = 0;
1710 idx++;
1712 if (has_normal) {
1713 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1714 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1715 elements[idx].UsageIndex = 0;
1716 idx++;
1718 if (has_psize) {
1719 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1720 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1721 elements[idx].UsageIndex = 0;
1722 idx++;
1724 if (has_diffuse) {
1725 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1726 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1727 elements[idx].UsageIndex = 0;
1728 idx++;
1730 if (has_specular) {
1731 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1732 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1733 elements[idx].UsageIndex = 1;
1734 idx++;
1736 for (idx2 = 0; idx2 < num_textures; idx2++) {
1737 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1738 switch (numcoords) {
1739 case WINED3DFVF_TEXTUREFORMAT1:
1740 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1741 break;
1742 case WINED3DFVF_TEXTUREFORMAT2:
1743 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1744 break;
1745 case WINED3DFVF_TEXTUREFORMAT3:
1746 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1747 break;
1748 case WINED3DFVF_TEXTUREFORMAT4:
1749 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1750 break;
1752 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1753 elements[idx].UsageIndex = idx2;
1754 idx++;
1757 /* Now compute offsets, and initialize the rest of the fields */
1758 for (idx = 0, offset = 0; idx < size-1; idx++) {
1759 elements[idx].Stream = 0;
1760 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1761 elements[idx].Offset = offset;
1762 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1765 *ppVertexElements = elements;
1766 return size;
1769 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1770 WINED3DVERTEXELEMENT* elements = NULL;
1771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1772 unsigned int size;
1773 DWORD hr;
1775 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1776 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1778 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1779 HeapFree(GetProcessHeap(), 0, elements);
1780 if (hr != S_OK) return hr;
1782 return WINED3D_OK;
1785 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1786 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1788 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1789 HRESULT hr = WINED3D_OK;
1790 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1791 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1793 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1795 if (vertex_declaration) {
1796 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1799 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1801 if (WINED3D_OK != hr) {
1802 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1803 IWineD3DVertexShader_Release(*ppVertexShader);
1804 return WINED3DERR_INVALIDCALL;
1806 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1808 return WINED3D_OK;
1811 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1813 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1814 HRESULT hr = WINED3D_OK;
1816 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1817 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1818 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1819 if (WINED3D_OK == hr) {
1820 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1821 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1822 } else {
1823 WARN("(%p) : Failed to create pixel shader\n", This);
1826 return hr;
1829 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1831 IWineD3DPaletteImpl *object;
1832 HRESULT hr;
1833 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1835 /* Create the new object */
1836 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1837 if(!object) {
1838 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1839 return E_OUTOFMEMORY;
1842 object->lpVtbl = &IWineD3DPalette_Vtbl;
1843 object->ref = 1;
1844 object->Flags = Flags;
1845 object->parent = Parent;
1846 object->wineD3DDevice = This;
1847 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1849 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1851 if(!object->hpal) {
1852 HeapFree( GetProcessHeap(), 0, object);
1853 return E_OUTOFMEMORY;
1856 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1857 if(FAILED(hr)) {
1858 IWineD3DPalette_Release((IWineD3DPalette *) object);
1859 return hr;
1862 *Palette = (IWineD3DPalette *) object;
1864 return WINED3D_OK;
1867 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1868 HBITMAP hbm;
1869 BITMAP bm;
1870 HRESULT hr;
1871 HDC dcb = NULL, dcs = NULL;
1872 WINEDDCOLORKEY colorkey;
1874 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1875 if(hbm)
1877 GetObjectA(hbm, sizeof(BITMAP), &bm);
1878 dcb = CreateCompatibleDC(NULL);
1879 if(!dcb) goto out;
1880 SelectObject(dcb, hbm);
1882 else
1884 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1885 * couldn't be loaded
1887 memset(&bm, 0, sizeof(bm));
1888 bm.bmWidth = 32;
1889 bm.bmHeight = 32;
1892 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1893 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1894 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1895 if(FAILED(hr)) {
1896 ERR("Wine logo requested, but failed to create surface\n");
1897 goto out;
1900 if(dcb) {
1901 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1902 if(FAILED(hr)) goto out;
1903 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1904 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1906 colorkey.dwColorSpaceLowValue = 0;
1907 colorkey.dwColorSpaceHighValue = 0;
1908 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1909 } else {
1910 /* Fill the surface with a white color to show that wined3d is there */
1911 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1914 out:
1915 if(dcb) {
1916 DeleteDC(dcb);
1918 if(hbm) {
1919 DeleteObject(hbm);
1921 return;
1924 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1926 IWineD3DSwapChainImpl *swapchain = NULL;
1927 HRESULT hr;
1928 DWORD state;
1930 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1931 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1933 /* TODO: Test if OpenGL is compiled in and loaded */
1935 TRACE("(%p) : Creating stateblock\n", This);
1936 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1937 hr = IWineD3DDevice_CreateStateBlock(iface,
1938 WINED3DSBT_INIT,
1939 (IWineD3DStateBlock **)&This->stateBlock,
1940 NULL);
1941 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1942 WARN("Failed to create stateblock\n");
1943 goto err_out;
1945 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1946 This->updateStateBlock = This->stateBlock;
1947 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1949 hr = allocate_shader_constants(This->updateStateBlock);
1950 if (WINED3D_OK != hr) {
1951 goto err_out;
1954 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1955 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1956 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1958 /* Initialize the texture unit mapping to a 1:1 mapping */
1959 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1960 if (state < GL_LIMITS(fragment_samplers)) {
1961 This->texUnitMap[state] = state;
1962 This->rev_tex_unit_map[state] = state;
1963 } else {
1964 This->texUnitMap[state] = -1;
1965 This->rev_tex_unit_map[state] = -1;
1969 /* Setup the implicit swapchain */
1970 TRACE("Creating implicit swapchain\n");
1971 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1972 if (FAILED(hr) || !swapchain) {
1973 WARN("Failed to create implicit swapchain\n");
1974 goto err_out;
1977 This->NumberOfSwapChains = 1;
1978 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1979 if(!This->swapchains) {
1980 ERR("Out of memory!\n");
1981 goto err_out;
1983 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1985 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1986 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1987 This->render_targets[0] = swapchain->backBuffer[0];
1988 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1990 else {
1991 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1992 This->render_targets[0] = swapchain->frontBuffer;
1993 This->lastActiveRenderTarget = swapchain->frontBuffer;
1995 IWineD3DSurface_AddRef(This->render_targets[0]);
1996 This->activeContext = swapchain->context[0];
1997 This->lastThread = GetCurrentThreadId();
1999 /* Depth Stencil support */
2000 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2001 if (NULL != This->stencilBufferTarget) {
2002 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2005 /* Set up some starting GL setup */
2006 ENTER_GL();
2008 /* Setup all the devices defaults */
2009 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2010 #if 0
2011 IWineD3DImpl_CheckGraphicsMemory();
2012 #endif
2014 { /* Set a default viewport */
2015 WINED3DVIEWPORT vp;
2016 vp.X = 0;
2017 vp.Y = 0;
2018 vp.Width = pPresentationParameters->BackBufferWidth;
2019 vp.Height = pPresentationParameters->BackBufferHeight;
2020 vp.MinZ = 0.0f;
2021 vp.MaxZ = 1.0f;
2022 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2025 /* Initialize the current view state */
2026 This->view_ident = 1;
2027 This->contexts[0]->last_was_rhw = 0;
2028 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2029 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2031 switch(wined3d_settings.offscreen_rendering_mode) {
2032 case ORM_FBO:
2033 case ORM_PBUFFER:
2034 This->offscreenBuffer = GL_BACK;
2035 break;
2037 case ORM_BACKBUFFER:
2039 if(GL_LIMITS(aux_buffers) > 0) {
2040 TRACE("Using auxilliary buffer for offscreen rendering\n");
2041 This->offscreenBuffer = GL_AUX0;
2042 } else {
2043 TRACE("Using back buffer for offscreen rendering\n");
2044 This->offscreenBuffer = GL_BACK;
2049 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2050 LEAVE_GL();
2052 /* Clear the screen */
2053 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2054 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2055 0x00, 1.0, 0);
2057 This->d3d_initialized = TRUE;
2059 if(wined3d_settings.logo) {
2060 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2062 return WINED3D_OK;
2064 err_out:
2065 HeapFree(GetProcessHeap(), 0, This->render_targets);
2066 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2067 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2068 HeapFree(GetProcessHeap(), 0, This->swapchains);
2069 This->NumberOfSwapChains = 0;
2070 if(swapchain) {
2071 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2073 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2074 if(This->stateBlock) {
2075 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2076 This->stateBlock = NULL;
2078 return hr;
2081 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2083 int sampler;
2084 UINT i;
2085 TRACE("(%p)\n", This);
2087 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2089 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2090 * it was created. Thus make sure a context is active for the glDelete* calls
2092 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2094 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2096 TRACE("Deleting high order patches\n");
2097 for(i = 0; i < PATCHMAP_SIZE; i++) {
2098 struct list *e1, *e2;
2099 struct WineD3DRectPatch *patch;
2100 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2101 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2102 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2106 /* Delete the palette conversion shader if it is around */
2107 if(This->paletteConversionShader) {
2108 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2109 This->paletteConversionShader = 0;
2112 /* Delete the pbuffer context if there is any */
2113 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2115 /* Delete the mouse cursor texture */
2116 if(This->cursorTexture) {
2117 ENTER_GL();
2118 glDeleteTextures(1, &This->cursorTexture);
2119 LEAVE_GL();
2120 This->cursorTexture = 0;
2123 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2124 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2126 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2127 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2130 /* Release the update stateblock */
2131 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2132 if(This->updateStateBlock != This->stateBlock)
2133 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2135 This->updateStateBlock = NULL;
2137 { /* because were not doing proper internal refcounts releasing the primary state block
2138 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2139 to set this->stateBlock = NULL; first */
2140 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2141 This->stateBlock = NULL;
2143 /* Release the stateblock */
2144 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2145 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2149 /* Release the buffers (with sanity checks)*/
2150 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2151 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2152 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2153 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2155 This->stencilBufferTarget = NULL;
2157 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2158 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2159 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2161 TRACE("Setting rendertarget to NULL\n");
2162 This->render_targets[0] = NULL;
2164 if (This->auto_depth_stencil_buffer) {
2165 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2166 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2168 This->auto_depth_stencil_buffer = NULL;
2171 for(i=0; i < This->NumberOfSwapChains; i++) {
2172 TRACE("Releasing the implicit swapchain %d\n", i);
2173 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2174 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2178 HeapFree(GetProcessHeap(), 0, This->swapchains);
2179 This->swapchains = NULL;
2180 This->NumberOfSwapChains = 0;
2182 HeapFree(GetProcessHeap(), 0, This->render_targets);
2183 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2184 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2185 This->render_targets = NULL;
2186 This->fbo_color_attachments = NULL;
2187 This->draw_buffers = NULL;
2190 This->d3d_initialized = FALSE;
2191 return WINED3D_OK;
2194 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2196 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2198 /* Setup the window for fullscreen mode */
2199 if(fullscreen && !This->ddraw_fullscreen) {
2200 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2201 } else if(!fullscreen && This->ddraw_fullscreen) {
2202 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2205 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2206 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2207 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2208 * separately.
2210 This->ddraw_fullscreen = fullscreen;
2213 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2214 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2215 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2217 * There is no way to deactivate thread safety once it is enabled.
2219 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2222 /*For now just store the flag(needed in case of ddraw) */
2223 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2225 return;
2228 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2229 DEVMODEW devmode;
2230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2231 LONG ret;
2232 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2233 RECT clip_rc;
2235 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2237 /* Resize the screen even without a window:
2238 * The app could have unset it with SetCooperativeLevel, but not called
2239 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2240 * but we don't have any hwnd
2243 memset(&devmode, 0, sizeof(devmode));
2244 devmode.dmSize = sizeof(devmode);
2245 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2246 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2247 devmode.dmPelsWidth = pMode->Width;
2248 devmode.dmPelsHeight = pMode->Height;
2250 devmode.dmDisplayFrequency = pMode->RefreshRate;
2251 if (pMode->RefreshRate != 0) {
2252 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2255 /* Only change the mode if necessary */
2256 if( (This->ddraw_width == pMode->Width) &&
2257 (This->ddraw_height == pMode->Height) &&
2258 (This->ddraw_format == pMode->Format) &&
2259 (pMode->RefreshRate == 0) ) {
2260 return WINED3D_OK;
2263 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2264 if (ret != DISP_CHANGE_SUCCESSFUL) {
2265 if(devmode.dmDisplayFrequency != 0) {
2266 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2267 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2268 devmode.dmDisplayFrequency = 0;
2269 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2271 if(ret != DISP_CHANGE_SUCCESSFUL) {
2272 return WINED3DERR_NOTAVAILABLE;
2276 /* Store the new values */
2277 This->ddraw_width = pMode->Width;
2278 This->ddraw_height = pMode->Height;
2279 This->ddraw_format = pMode->Format;
2281 /* Only do this with a window of course */
2282 if(This->ddraw_window)
2283 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2285 /* And finally clip mouse to our screen */
2286 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2287 ClipCursor(&clip_rc);
2289 return WINED3D_OK;
2292 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2294 *ppD3D= This->wineD3D;
2295 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2296 IWineD3D_AddRef(*ppD3D);
2297 return WINED3D_OK;
2300 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2303 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2304 (This->adapter->TextureRam/(1024*1024)),
2305 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2306 /* return simulated texture memory left */
2307 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2312 /*****
2313 * Get / Set FVF
2314 *****/
2315 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2318 /* Update the current state block */
2319 This->updateStateBlock->changed.fvf = TRUE;
2321 if(This->updateStateBlock->fvf == fvf) {
2322 TRACE("Application is setting the old fvf over, nothing to do\n");
2323 return WINED3D_OK;
2326 This->updateStateBlock->fvf = fvf;
2327 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2329 return WINED3D_OK;
2333 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2335 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2336 *pfvf = This->stateBlock->fvf;
2337 return WINED3D_OK;
2340 /*****
2341 * Get / Set Stream Source
2342 *****/
2343 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 IWineD3DVertexBuffer *oldSrc;
2347 if (StreamNumber >= MAX_STREAMS) {
2348 WARN("Stream out of range %d\n", StreamNumber);
2349 return WINED3DERR_INVALIDCALL;
2350 } else if(OffsetInBytes & 0x3) {
2351 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2352 return WINED3DERR_INVALIDCALL;
2355 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2356 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2358 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2360 if(oldSrc == pStreamData &&
2361 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2362 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2363 TRACE("Application is setting the old values over, nothing to do\n");
2364 return WINED3D_OK;
2367 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2368 if (pStreamData) {
2369 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2370 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2373 /* Handle recording of state blocks */
2374 if (This->isRecordingState) {
2375 TRACE("Recording... not performing anything\n");
2376 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2377 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2378 return WINED3D_OK;
2381 /* Need to do a getParent and pass the references up */
2382 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2383 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2384 so for now, just count internally */
2385 if (pStreamData != NULL) {
2386 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2387 InterlockedIncrement(&vbImpl->bindCount);
2388 IWineD3DVertexBuffer_AddRef(pStreamData);
2390 if (oldSrc != NULL) {
2391 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2392 IWineD3DVertexBuffer_Release(oldSrc);
2395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2397 return WINED3D_OK;
2400 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2404 This->stateBlock->streamSource[StreamNumber],
2405 This->stateBlock->streamOffset[StreamNumber],
2406 This->stateBlock->streamStride[StreamNumber]);
2408 if (StreamNumber >= MAX_STREAMS) {
2409 WARN("Stream out of range %d\n", StreamNumber);
2410 return WINED3DERR_INVALIDCALL;
2412 *pStream = This->stateBlock->streamSource[StreamNumber];
2413 *pStride = This->stateBlock->streamStride[StreamNumber];
2414 if (pOffset) {
2415 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2418 if (*pStream != NULL) {
2419 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2421 return WINED3D_OK;
2424 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2426 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2427 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2429 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2430 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2432 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2433 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2435 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2436 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2437 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2440 return WINED3D_OK;
2443 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2446 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2447 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2449 TRACE("(%p) : returning %d\n", This, *Divider);
2451 return WINED3D_OK;
2454 /*****
2455 * Get / Set & Multiply Transform
2456 *****/
2457 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2460 /* Most of this routine, comments included copied from ddraw tree initially: */
2461 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2463 /* Handle recording of state blocks */
2464 if (This->isRecordingState) {
2465 TRACE("Recording... not performing anything\n");
2466 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2467 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2468 return WINED3D_OK;
2472 * If the new matrix is the same as the current one,
2473 * we cut off any further processing. this seems to be a reasonable
2474 * optimization because as was noticed, some apps (warcraft3 for example)
2475 * tend towards setting the same matrix repeatedly for some reason.
2477 * From here on we assume that the new matrix is different, wherever it matters.
2479 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2480 TRACE("The app is setting the same matrix over again\n");
2481 return WINED3D_OK;
2482 } else {
2483 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2487 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2488 where ViewMat = Camera space, WorldMat = world space.
2490 In OpenGL, camera and world space is combined into GL_MODELVIEW
2491 matrix. The Projection matrix stay projection matrix.
2494 /* Capture the times we can just ignore the change for now */
2495 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2496 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2497 /* Handled by the state manager */
2500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2501 return WINED3D_OK;
2504 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2507 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2508 return WINED3D_OK;
2511 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2512 WINED3DMATRIX *mat = NULL;
2513 WINED3DMATRIX temp;
2515 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2516 * below means it will be recorded in a state block change, but it
2517 * works regardless where it is recorded.
2518 * If this is found to be wrong, change to StateBlock.
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2523 if (State < HIGHEST_TRANSFORMSTATE)
2525 mat = &This->updateStateBlock->transforms[State];
2526 } else {
2527 FIXME("Unhandled transform state!!\n");
2530 multiply_matrix(&temp, mat, pMatrix);
2532 /* Apply change via set transform - will reapply to eg. lights this way */
2533 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2536 /*****
2537 * Get / Set Light
2538 *****/
2539 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2540 you can reference any indexes you want as long as that number max are enabled at any
2541 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2542 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2543 but when recording, just build a chain pretty much of commands to be replayed. */
2545 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2546 float rho;
2547 PLIGHTINFOEL *object = NULL;
2548 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2549 struct list *e;
2551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2552 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2554 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2555 * the gl driver.
2557 if(!pLight) {
2558 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2559 return WINED3DERR_INVALIDCALL;
2562 switch(pLight->Type) {
2563 case WINED3DLIGHT_POINT:
2564 case WINED3DLIGHT_SPOT:
2565 case WINED3DLIGHT_PARALLELPOINT:
2566 case WINED3DLIGHT_GLSPOT:
2567 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2568 * most wanted
2570 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2571 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2572 return WINED3DERR_INVALIDCALL;
2574 break;
2576 case WINED3DLIGHT_DIRECTIONAL:
2577 /* Ignores attenuation */
2578 break;
2580 default:
2581 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2582 return WINED3DERR_INVALIDCALL;
2585 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2586 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2587 if(object->OriginalIndex == Index) break;
2588 object = NULL;
2591 if(!object) {
2592 TRACE("Adding new light\n");
2593 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2594 if(!object) {
2595 ERR("Out of memory error when allocating a light\n");
2596 return E_OUTOFMEMORY;
2598 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2599 object->glIndex = -1;
2600 object->OriginalIndex = Index;
2601 object->changed = TRUE;
2604 /* Initialize the object */
2605 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,
2606 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2607 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2608 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2609 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2610 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2611 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2613 /* Save away the information */
2614 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2616 switch (pLight->Type) {
2617 case WINED3DLIGHT_POINT:
2618 /* Position */
2619 object->lightPosn[0] = pLight->Position.x;
2620 object->lightPosn[1] = pLight->Position.y;
2621 object->lightPosn[2] = pLight->Position.z;
2622 object->lightPosn[3] = 1.0f;
2623 object->cutoff = 180.0f;
2624 /* FIXME: Range */
2625 break;
2627 case WINED3DLIGHT_DIRECTIONAL:
2628 /* Direction */
2629 object->lightPosn[0] = -pLight->Direction.x;
2630 object->lightPosn[1] = -pLight->Direction.y;
2631 object->lightPosn[2] = -pLight->Direction.z;
2632 object->lightPosn[3] = 0.0;
2633 object->exponent = 0.0f;
2634 object->cutoff = 180.0f;
2635 break;
2637 case WINED3DLIGHT_SPOT:
2638 /* Position */
2639 object->lightPosn[0] = pLight->Position.x;
2640 object->lightPosn[1] = pLight->Position.y;
2641 object->lightPosn[2] = pLight->Position.z;
2642 object->lightPosn[3] = 1.0;
2644 /* Direction */
2645 object->lightDirn[0] = pLight->Direction.x;
2646 object->lightDirn[1] = pLight->Direction.y;
2647 object->lightDirn[2] = pLight->Direction.z;
2648 object->lightDirn[3] = 1.0;
2651 * opengl-ish and d3d-ish spot lights use too different models for the
2652 * light "intensity" as a function of the angle towards the main light direction,
2653 * so we only can approximate very roughly.
2654 * however spot lights are rather rarely used in games (if ever used at all).
2655 * furthermore if still used, probably nobody pays attention to such details.
2657 if (pLight->Falloff == 0) {
2658 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2659 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2660 * will always be 1.0 for both of them, and we don't have to care for the
2661 * rest of the rather complex calculation
2663 object->exponent = 0;
2664 } else {
2665 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2666 if (rho < 0.0001) rho = 0.0001f;
2667 object->exponent = -0.3/log(cos(rho/2));
2669 if (object->exponent > 128.0) {
2670 object->exponent = 128.0;
2672 object->cutoff = pLight->Phi*90/M_PI;
2674 /* FIXME: Range */
2675 break;
2677 default:
2678 FIXME("Unrecognized light type %d\n", pLight->Type);
2681 /* Update the live definitions if the light is currently assigned a glIndex */
2682 if (object->glIndex != -1 && !This->isRecordingState) {
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2685 return WINED3D_OK;
2688 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2689 PLIGHTINFOEL *lightInfo = NULL;
2690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2692 struct list *e;
2693 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2695 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2696 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2697 if(lightInfo->OriginalIndex == Index) break;
2698 lightInfo = NULL;
2701 if (lightInfo == NULL) {
2702 TRACE("Light information requested but light not defined\n");
2703 return WINED3DERR_INVALIDCALL;
2706 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2707 return WINED3D_OK;
2710 /*****
2711 * Get / Set Light Enable
2712 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2713 *****/
2714 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2715 PLIGHTINFOEL *lightInfo = NULL;
2716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2717 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2718 struct list *e;
2719 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2721 /* Tests show true = 128...not clear why */
2722 Enable = Enable? 128: 0;
2724 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2725 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2726 if(lightInfo->OriginalIndex == Index) break;
2727 lightInfo = NULL;
2729 TRACE("Found light: %p\n", lightInfo);
2731 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2732 if (lightInfo == NULL) {
2734 TRACE("Light enabled requested but light not defined, so defining one!\n");
2735 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2737 /* Search for it again! Should be fairly quick as near head of list */
2738 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2739 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2740 if(lightInfo->OriginalIndex == Index) break;
2741 lightInfo = NULL;
2743 if (lightInfo == NULL) {
2744 FIXME("Adding default lights has failed dismally\n");
2745 return WINED3DERR_INVALIDCALL;
2749 lightInfo->enabledChanged = TRUE;
2750 if(!Enable) {
2751 if(lightInfo->glIndex != -1) {
2752 if(!This->isRecordingState) {
2753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2756 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2757 lightInfo->glIndex = -1;
2758 } else {
2759 TRACE("Light already disabled, nothing to do\n");
2761 lightInfo->enabled = FALSE;
2762 } else {
2763 lightInfo->enabled = TRUE;
2764 if (lightInfo->glIndex != -1) {
2765 /* nop */
2766 TRACE("Nothing to do as light was enabled\n");
2767 } else {
2768 int i;
2769 /* Find a free gl light */
2770 for(i = 0; i < This->maxConcurrentLights; i++) {
2771 if(This->stateBlock->activeLights[i] == NULL) {
2772 This->stateBlock->activeLights[i] = lightInfo;
2773 lightInfo->glIndex = i;
2774 break;
2777 if(lightInfo->glIndex == -1) {
2778 /* Our tests show that Windows returns D3D_OK in this situation, even with
2779 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2780 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2781 * as well for those lights.
2783 * TODO: Test how this affects rendering
2785 FIXME("Too many concurrently active lights\n");
2786 return WINED3D_OK;
2789 /* i == lightInfo->glIndex */
2790 if(!This->isRecordingState) {
2791 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2796 return WINED3D_OK;
2799 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2801 PLIGHTINFOEL *lightInfo = NULL;
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 struct list *e;
2804 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2805 TRACE("(%p) : for idx(%d)\n", This, Index);
2807 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2808 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2809 if(lightInfo->OriginalIndex == Index) break;
2810 lightInfo = NULL;
2813 if (lightInfo == NULL) {
2814 TRACE("Light enabled state requested but light not defined\n");
2815 return WINED3DERR_INVALIDCALL;
2817 /* true is 128 according to SetLightEnable */
2818 *pEnable = lightInfo->enabled ? 128 : 0;
2819 return WINED3D_OK;
2822 /*****
2823 * Get / Set Clip Planes
2824 *****/
2825 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2827 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2829 /* Validate Index */
2830 if (Index >= GL_LIMITS(clipplanes)) {
2831 TRACE("Application has requested clipplane this device doesn't support\n");
2832 return WINED3DERR_INVALIDCALL;
2835 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2837 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2838 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2839 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2840 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2841 TRACE("Application is setting old values over, nothing to do\n");
2842 return WINED3D_OK;
2845 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2846 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2847 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2848 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2850 /* Handle recording of state blocks */
2851 if (This->isRecordingState) {
2852 TRACE("Recording... not performing anything\n");
2853 return WINED3D_OK;
2856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2858 return WINED3D_OK;
2861 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 TRACE("(%p) : for idx %d\n", This, Index);
2865 /* Validate Index */
2866 if (Index >= GL_LIMITS(clipplanes)) {
2867 TRACE("Application has requested clipplane this device doesn't support\n");
2868 return WINED3DERR_INVALIDCALL;
2871 pPlane[0] = This->stateBlock->clipplane[Index][0];
2872 pPlane[1] = This->stateBlock->clipplane[Index][1];
2873 pPlane[2] = This->stateBlock->clipplane[Index][2];
2874 pPlane[3] = This->stateBlock->clipplane[Index][3];
2875 return WINED3D_OK;
2878 /*****
2879 * Get / Set Clip Plane Status
2880 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2881 *****/
2882 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 FIXME("(%p) : stub\n", This);
2885 if (NULL == pClipStatus) {
2886 return WINED3DERR_INVALIDCALL;
2888 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2889 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2890 return WINED3D_OK;
2893 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 FIXME("(%p) : stub\n", This);
2896 if (NULL == pClipStatus) {
2897 return WINED3DERR_INVALIDCALL;
2899 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2900 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2901 return WINED3D_OK;
2904 /*****
2905 * Get / Set Material
2906 *****/
2907 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2910 This->updateStateBlock->changed.material = TRUE;
2911 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2913 /* Handle recording of state blocks */
2914 if (This->isRecordingState) {
2915 TRACE("Recording... not performing anything\n");
2916 return WINED3D_OK;
2919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2920 return WINED3D_OK;
2923 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2925 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2926 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2927 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2928 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2929 pMaterial->Ambient.b, pMaterial->Ambient.a);
2930 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2931 pMaterial->Specular.b, pMaterial->Specular.a);
2932 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2933 pMaterial->Emissive.b, pMaterial->Emissive.a);
2934 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2936 return WINED3D_OK;
2939 /*****
2940 * Get / Set Indices
2941 *****/
2942 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2944 IWineD3DIndexBuffer *oldIdxs;
2946 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2947 oldIdxs = This->updateStateBlock->pIndexData;
2949 This->updateStateBlock->changed.indices = TRUE;
2950 This->updateStateBlock->pIndexData = pIndexData;
2952 /* Handle recording of state blocks */
2953 if (This->isRecordingState) {
2954 TRACE("Recording... not performing anything\n");
2955 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2956 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2957 return WINED3D_OK;
2960 if(oldIdxs != pIndexData) {
2961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2962 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2963 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2965 return WINED3D_OK;
2968 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2971 *ppIndexData = This->stateBlock->pIndexData;
2973 /* up ref count on ppindexdata */
2974 if (*ppIndexData) {
2975 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2976 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2977 }else{
2978 TRACE("(%p) No index data set\n", This);
2980 TRACE("Returning %p\n", *ppIndexData);
2982 return WINED3D_OK;
2985 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2986 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 TRACE("(%p)->(%d)\n", This, BaseIndex);
2990 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2991 TRACE("Application is setting the old value over, nothing to do\n");
2992 return WINED3D_OK;
2995 This->updateStateBlock->baseVertexIndex = BaseIndex;
2997 if (This->isRecordingState) {
2998 TRACE("Recording... not performing anything\n");
2999 return WINED3D_OK;
3001 /* The base vertex index affects the stream sources */
3002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3003 return WINED3D_OK;
3006 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3008 TRACE("(%p) : base_index %p\n", This, base_index);
3010 *base_index = This->stateBlock->baseVertexIndex;
3012 TRACE("Returning %u\n", *base_index);
3014 return WINED3D_OK;
3017 /*****
3018 * Get / Set Viewports
3019 *****/
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3023 TRACE("(%p)\n", This);
3024 This->updateStateBlock->changed.viewport = TRUE;
3025 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3027 /* Handle recording of state blocks */
3028 if (This->isRecordingState) {
3029 TRACE("Recording... not performing anything\n");
3030 return WINED3D_OK;
3033 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3034 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3037 return WINED3D_OK;
3041 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 TRACE("(%p)\n", This);
3044 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3045 return WINED3D_OK;
3048 /*****
3049 * Get / Set Render States
3050 * TODO: Verify against dx9 definitions
3051 *****/
3052 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 DWORD oldValue = This->stateBlock->renderState[State];
3057 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3059 This->updateStateBlock->changed.renderState[State] = TRUE;
3060 This->updateStateBlock->renderState[State] = Value;
3062 /* Handle recording of state blocks */
3063 if (This->isRecordingState) {
3064 TRACE("Recording... not performing anything\n");
3065 return WINED3D_OK;
3068 /* Compared here and not before the assignment to allow proper stateblock recording */
3069 if(Value == oldValue) {
3070 TRACE("Application is setting the old value over, nothing to do\n");
3071 } else {
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3075 return WINED3D_OK;
3078 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3081 *pValue = This->stateBlock->renderState[State];
3082 return WINED3D_OK;
3085 /*****
3086 * Get / Set Sampler States
3087 * TODO: Verify against dx9 definitions
3088 *****/
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3092 DWORD oldValue;
3094 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3095 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3097 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3098 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3101 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3102 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3103 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3106 * SetSampler is designed to allow for more than the standard up to 8 textures
3107 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3108 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3110 * http://developer.nvidia.com/object/General_FAQ.html#t6
3112 * There are two new settings for GForce
3113 * the sampler one:
3114 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3115 * and the texture one:
3116 * GL_MAX_TEXTURE_COORDS_ARB.
3117 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3118 ******************/
3120 oldValue = This->stateBlock->samplerState[Sampler][Type];
3121 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3122 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3124 /* Handle recording of state blocks */
3125 if (This->isRecordingState) {
3126 TRACE("Recording... not performing anything\n");
3127 return WINED3D_OK;
3130 if(oldValue == Value) {
3131 TRACE("Application is setting the old value over, nothing to do\n");
3132 return WINED3D_OK;
3135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3137 return WINED3D_OK;
3140 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3144 This, Sampler, debug_d3dsamplerstate(Type), Type);
3146 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3147 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3150 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3151 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3152 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3154 *Value = This->stateBlock->samplerState[Sampler][Type];
3155 TRACE("(%p) : Returning %#x\n", This, *Value);
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 This->updateStateBlock->changed.scissorRect = TRUE;
3164 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3165 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3166 return WINED3D_OK;
3168 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3170 if(This->isRecordingState) {
3171 TRACE("Recording... not performing anything\n");
3172 return WINED3D_OK;
3175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3177 return WINED3D_OK;
3180 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 *pRect = This->updateStateBlock->scissorRect;
3184 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3190 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3192 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3194 This->updateStateBlock->vertexDecl = pDecl;
3195 This->updateStateBlock->changed.vertexDecl = TRUE;
3197 if (This->isRecordingState) {
3198 TRACE("Recording... not performing anything\n");
3199 return WINED3D_OK;
3200 } else if(pDecl == oldDecl) {
3201 /* Checked after the assignment to allow proper stateblock recording */
3202 TRACE("Application is setting the old declaration over, nothing to do\n");
3203 return WINED3D_OK;
3206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3215 *ppDecl = This->stateBlock->vertexDecl;
3216 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3217 return WINED3D_OK;
3220 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3224 This->updateStateBlock->vertexShader = pShader;
3225 This->updateStateBlock->changed.vertexShader = TRUE;
3227 if (This->isRecordingState) {
3228 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3229 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3230 TRACE("Recording... not performing anything\n");
3231 return WINED3D_OK;
3232 } else if(oldShader == pShader) {
3233 /* Checked here to allow proper stateblock recording */
3234 TRACE("App is setting the old shader over, nothing to do\n");
3235 return WINED3D_OK;
3238 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3239 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3240 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3244 return WINED3D_OK;
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3250 if (NULL == ppShader) {
3251 return WINED3DERR_INVALIDCALL;
3253 *ppShader = This->stateBlock->vertexShader;
3254 if( NULL != *ppShader)
3255 IWineD3DVertexShader_AddRef(*ppShader);
3257 TRACE("(%p) : returning %p\n", This, *ppShader);
3258 return WINED3D_OK;
3261 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3262 IWineD3DDevice *iface,
3263 UINT start,
3264 CONST BOOL *srcData,
3265 UINT count) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 int i, cnt = min(count, MAX_CONST_B - start);
3270 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3271 iface, srcData, start, count);
3273 if (srcData == NULL || cnt < 0)
3274 return WINED3DERR_INVALIDCALL;
3276 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3277 for (i = 0; i < cnt; i++)
3278 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3280 for (i = start; i < cnt + start; ++i) {
3281 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3286 return WINED3D_OK;
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3290 IWineD3DDevice *iface,
3291 UINT start,
3292 BOOL *dstData,
3293 UINT count) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 int cnt = min(count, MAX_CONST_B - start);
3298 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3299 iface, dstData, start, count);
3301 if (dstData == NULL || cnt < 0)
3302 return WINED3DERR_INVALIDCALL;
3304 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3305 return WINED3D_OK;
3308 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3309 IWineD3DDevice *iface,
3310 UINT start,
3311 CONST int *srcData,
3312 UINT count) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 int i, cnt = min(count, MAX_CONST_I - start);
3317 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3318 iface, srcData, start, count);
3320 if (srcData == NULL || cnt < 0)
3321 return WINED3DERR_INVALIDCALL;
3323 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3324 for (i = 0; i < cnt; i++)
3325 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3326 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3328 for (i = start; i < cnt + start; ++i) {
3329 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3334 return WINED3D_OK;
3337 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3338 IWineD3DDevice *iface,
3339 UINT start,
3340 int *dstData,
3341 UINT count) {
3343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 int cnt = min(count, MAX_CONST_I - start);
3346 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3347 iface, dstData, start, count);
3349 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3350 return WINED3DERR_INVALIDCALL;
3352 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3353 return WINED3D_OK;
3356 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3357 IWineD3DDevice *iface,
3358 UINT start,
3359 CONST float *srcData,
3360 UINT count) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 int i;
3365 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3366 iface, srcData, start, count);
3368 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3369 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3370 return WINED3DERR_INVALIDCALL;
3372 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3373 if(TRACE_ON(d3d)) {
3374 for (i = 0; i < count; i++)
3375 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3376 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3379 for (i = start; i < count + start; ++i) {
3380 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3381 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3382 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3383 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3384 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3386 ptr->idx[ptr->count++] = i;
3387 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3393 return WINED3D_OK;
3396 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3397 IWineD3DDevice *iface,
3398 UINT start,
3399 float *dstData,
3400 UINT count) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3405 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3406 iface, dstData, start, count);
3408 if (dstData == NULL || cnt < 0)
3409 return WINED3DERR_INVALIDCALL;
3411 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3412 return WINED3D_OK;
3415 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3416 DWORD i;
3417 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3422 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3423 int i = This->rev_tex_unit_map[unit];
3424 int j = This->texUnitMap[stage];
3426 This->texUnitMap[stage] = unit;
3427 if (i != -1 && i != stage) {
3428 This->texUnitMap[i] = -1;
3431 This->rev_tex_unit_map[unit] = stage;
3432 if (j != -1 && j != unit) {
3433 This->rev_tex_unit_map[j] = -1;
3437 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3438 int i;
3440 for (i = 0; i < MAX_TEXTURES; ++i) {
3441 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3442 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3443 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3444 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3445 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3446 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3447 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3448 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3450 if (color_op == WINED3DTOP_DISABLE) {
3451 /* Not used, and disable higher stages */
3452 while (i < MAX_TEXTURES) {
3453 This->fixed_function_usage_map[i] = FALSE;
3454 ++i;
3456 break;
3459 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3460 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3461 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3462 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3463 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3464 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3465 This->fixed_function_usage_map[i] = TRUE;
3466 } else {
3467 This->fixed_function_usage_map[i] = FALSE;
3470 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3471 This->fixed_function_usage_map[i+1] = TRUE;
3476 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3477 int i, tex;
3479 device_update_fixed_function_usage_map(This);
3481 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3482 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3483 if (!This->fixed_function_usage_map[i]) continue;
3485 if (This->texUnitMap[i] != i) {
3486 device_map_stage(This, i, i);
3487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3488 markTextureStagesDirty(This, i);
3491 return;
3494 /* Now work out the mapping */
3495 tex = 0;
3496 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3497 if (!This->fixed_function_usage_map[i]) continue;
3499 if (This->texUnitMap[i] != tex) {
3500 device_map_stage(This, i, tex);
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3502 markTextureStagesDirty(This, i);
3505 ++tex;
3509 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3510 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3511 int i;
3513 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3514 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3515 device_map_stage(This, i, i);
3516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3517 if (i < MAX_TEXTURES) {
3518 markTextureStagesDirty(This, i);
3524 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3525 int current_mapping = This->rev_tex_unit_map[unit];
3527 if (current_mapping == -1) {
3528 /* Not currently used */
3529 return TRUE;
3532 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3533 /* Used by a fragment sampler */
3535 if (!pshader_sampler_tokens) {
3536 /* No pixel shader, check fixed function */
3537 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3540 /* Pixel shader, check the shader's sampler map */
3541 return !pshader_sampler_tokens[current_mapping];
3544 /* Used by a vertex sampler */
3545 return !vshader_sampler_tokens[current_mapping];
3548 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3549 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3550 DWORD *pshader_sampler_tokens = NULL;
3551 int start = GL_LIMITS(combined_samplers) - 1;
3552 int i;
3554 if (ps) {
3555 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3557 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3558 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3559 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3562 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3563 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3564 if (vshader_sampler_tokens[i]) {
3565 if (This->texUnitMap[vsampler_idx] != -1) {
3566 /* Already mapped somewhere */
3567 continue;
3570 while (start >= 0) {
3571 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3572 device_map_stage(This, vsampler_idx, start);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3575 --start;
3576 break;
3579 --start;
3585 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3586 BOOL vs = use_vs(This);
3587 BOOL ps = use_ps(This);
3589 * Rules are:
3590 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3591 * that would be really messy and require shader recompilation
3592 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3593 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3595 if (ps) {
3596 device_map_psamplers(This);
3597 } else {
3598 device_map_fixed_function_samplers(This);
3601 if (vs) {
3602 device_map_vsamplers(This, ps);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3608 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3609 This->updateStateBlock->pixelShader = pShader;
3610 This->updateStateBlock->changed.pixelShader = TRUE;
3612 /* Handle recording of state blocks */
3613 if (This->isRecordingState) {
3614 TRACE("Recording... not performing anything\n");
3617 if (This->isRecordingState) {
3618 TRACE("Recording... not performing anything\n");
3619 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3620 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3621 return WINED3D_OK;
3624 if(pShader == oldShader) {
3625 TRACE("App is setting the old pixel shader over, nothing to do\n");
3626 return WINED3D_OK;
3629 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3630 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3632 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3635 return WINED3D_OK;
3638 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3641 if (NULL == ppShader) {
3642 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3643 return WINED3DERR_INVALIDCALL;
3646 *ppShader = This->stateBlock->pixelShader;
3647 if (NULL != *ppShader) {
3648 IWineD3DPixelShader_AddRef(*ppShader);
3650 TRACE("(%p) : returning %p\n", This, *ppShader);
3651 return WINED3D_OK;
3654 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3655 IWineD3DDevice *iface,
3656 UINT start,
3657 CONST BOOL *srcData,
3658 UINT count) {
3660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3661 int i, cnt = min(count, MAX_CONST_B - start);
3663 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3664 iface, srcData, start, count);
3666 if (srcData == NULL || cnt < 0)
3667 return WINED3DERR_INVALIDCALL;
3669 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3670 for (i = 0; i < cnt; i++)
3671 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3673 for (i = start; i < cnt + start; ++i) {
3674 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3677 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3679 return WINED3D_OK;
3682 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3683 IWineD3DDevice *iface,
3684 UINT start,
3685 BOOL *dstData,
3686 UINT count) {
3688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3689 int cnt = min(count, MAX_CONST_B - start);
3691 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3692 iface, dstData, start, count);
3694 if (dstData == NULL || cnt < 0)
3695 return WINED3DERR_INVALIDCALL;
3697 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3698 return WINED3D_OK;
3701 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3702 IWineD3DDevice *iface,
3703 UINT start,
3704 CONST int *srcData,
3705 UINT count) {
3707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3708 int i, cnt = min(count, MAX_CONST_I - start);
3710 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3711 iface, srcData, start, count);
3713 if (srcData == NULL || cnt < 0)
3714 return WINED3DERR_INVALIDCALL;
3716 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3717 for (i = 0; i < cnt; i++)
3718 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3719 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3721 for (i = start; i < cnt + start; ++i) {
3722 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3727 return WINED3D_OK;
3730 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3731 IWineD3DDevice *iface,
3732 UINT start,
3733 int *dstData,
3734 UINT count) {
3736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3737 int cnt = min(count, MAX_CONST_I - start);
3739 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3740 iface, dstData, start, count);
3742 if (dstData == NULL || cnt < 0)
3743 return WINED3DERR_INVALIDCALL;
3745 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3746 return WINED3D_OK;
3749 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3750 IWineD3DDevice *iface,
3751 UINT start,
3752 CONST float *srcData,
3753 UINT count) {
3755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3756 int i;
3758 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3759 iface, srcData, start, count);
3761 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3762 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3763 return WINED3DERR_INVALIDCALL;
3765 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3766 if(TRACE_ON(d3d)) {
3767 for (i = 0; i < count; i++)
3768 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3769 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3772 for (i = start; i < count + start; ++i) {
3773 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3774 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3775 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3776 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3777 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3779 ptr->idx[ptr->count++] = i;
3780 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3786 return WINED3D_OK;
3789 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3790 IWineD3DDevice *iface,
3791 UINT start,
3792 float *dstData,
3793 UINT count) {
3795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3796 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3799 iface, dstData, start, count);
3801 if (dstData == NULL || cnt < 0)
3802 return WINED3DERR_INVALIDCALL;
3804 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3805 return WINED3D_OK;
3808 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3809 static HRESULT
3810 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3811 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3812 unsigned int i;
3813 DWORD DestFVF = dest->fvf;
3814 WINED3DVIEWPORT vp;
3815 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3816 BOOL doClip;
3817 int numTextures;
3819 if (lpStrideData->u.s.normal.lpData) {
3820 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3823 if (lpStrideData->u.s.position.lpData == NULL) {
3824 ERR("Source has no position mask\n");
3825 return WINED3DERR_INVALIDCALL;
3828 /* We might access VBOs from this code, so hold the lock */
3829 ENTER_GL();
3831 if (dest->resource.allocatedMemory == NULL) {
3832 /* This may happen if we do direct locking into a vbo. Unlikely,
3833 * but theoretically possible(ddraw processvertices test)
3835 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3836 if(!dest->resource.allocatedMemory) {
3837 LEAVE_GL();
3838 ERR("Out of memory\n");
3839 return E_OUTOFMEMORY;
3841 if(dest->vbo) {
3842 void *src;
3843 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3844 checkGLcall("glBindBufferARB");
3845 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3846 if(src) {
3847 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3849 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3850 checkGLcall("glUnmapBufferARB");
3854 /* Get a pointer into the destination vbo(create one if none exists) and
3855 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3857 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3858 dest->Flags |= VBFLAG_CREATEVBO;
3859 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
3862 if(dest->vbo) {
3863 unsigned char extrabytes = 0;
3864 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3865 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3866 * this may write 4 extra bytes beyond the area that should be written
3868 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3869 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3870 if(!dest_conv_addr) {
3871 ERR("Out of memory\n");
3872 /* Continue without storing converted vertices */
3874 dest_conv = dest_conv_addr;
3877 /* Should I clip?
3878 * a) WINED3DRS_CLIPPING is enabled
3879 * b) WINED3DVOP_CLIP is passed
3881 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3882 static BOOL warned = FALSE;
3884 * The clipping code is not quite correct. Some things need
3885 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3886 * so disable clipping for now.
3887 * (The graphics in Half-Life are broken, and my processvertices
3888 * test crashes with IDirect3DDevice3)
3889 doClip = TRUE;
3891 doClip = FALSE;
3892 if(!warned) {
3893 warned = TRUE;
3894 FIXME("Clipping is broken and disabled for now\n");
3896 } else doClip = FALSE;
3897 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3899 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3900 WINED3DTS_VIEW,
3901 &view_mat);
3902 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3903 WINED3DTS_PROJECTION,
3904 &proj_mat);
3905 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3906 WINED3DTS_WORLDMATRIX(0),
3907 &world_mat);
3909 TRACE("View mat:\n");
3910 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);
3911 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);
3912 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);
3913 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);
3915 TRACE("Proj mat:\n");
3916 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);
3917 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);
3918 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);
3919 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);
3921 TRACE("World mat:\n");
3922 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);
3923 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);
3924 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);
3925 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);
3927 /* Get the viewport */
3928 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3929 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3930 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3932 multiply_matrix(&mat,&view_mat,&world_mat);
3933 multiply_matrix(&mat,&proj_mat,&mat);
3935 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3937 for (i = 0; i < dwCount; i+= 1) {
3938 unsigned int tex_index;
3940 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3941 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3942 /* The position first */
3943 float *p =
3944 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3945 float x, y, z, rhw;
3946 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3948 /* Multiplication with world, view and projection matrix */
3949 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);
3950 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);
3951 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);
3952 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);
3954 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3956 /* WARNING: The following things are taken from d3d7 and were not yet checked
3957 * against d3d8 or d3d9!
3960 /* Clipping conditions: From
3961 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3963 * A vertex is clipped if it does not match the following requirements
3964 * -rhw < x <= rhw
3965 * -rhw < y <= rhw
3966 * 0 < z <= rhw
3967 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3969 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3970 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3974 if( !doClip ||
3975 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3976 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3977 ( rhw > eps ) ) ) {
3979 /* "Normal" viewport transformation (not clipped)
3980 * 1) The values are divided by rhw
3981 * 2) The y axis is negative, so multiply it with -1
3982 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3983 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3984 * 4) Multiply x with Width/2 and add Width/2
3985 * 5) The same for the height
3986 * 6) Add the viewpoint X and Y to the 2D coordinates and
3987 * The minimum Z value to z
3988 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3990 * Well, basically it's simply a linear transformation into viewport
3991 * coordinates
3994 x /= rhw;
3995 y /= rhw;
3996 z /= rhw;
3998 y *= -1;
4000 x *= vp.Width / 2;
4001 y *= vp.Height / 2;
4002 z *= vp.MaxZ - vp.MinZ;
4004 x += vp.Width / 2 + vp.X;
4005 y += vp.Height / 2 + vp.Y;
4006 z += vp.MinZ;
4008 rhw = 1 / rhw;
4009 } else {
4010 /* That vertex got clipped
4011 * Contrary to OpenGL it is not dropped completely, it just
4012 * undergoes a different calculation.
4014 TRACE("Vertex got clipped\n");
4015 x += rhw;
4016 y += rhw;
4018 x /= 2;
4019 y /= 2;
4021 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4022 * outside of the main vertex buffer memory. That needs some more
4023 * investigation...
4027 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4030 ( (float *) dest_ptr)[0] = x;
4031 ( (float *) dest_ptr)[1] = y;
4032 ( (float *) dest_ptr)[2] = z;
4033 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4035 dest_ptr += 3 * sizeof(float);
4037 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4038 dest_ptr += sizeof(float);
4041 if(dest_conv) {
4042 float w = 1 / rhw;
4043 ( (float *) dest_conv)[0] = x * w;
4044 ( (float *) dest_conv)[1] = y * w;
4045 ( (float *) dest_conv)[2] = z * w;
4046 ( (float *) dest_conv)[3] = w;
4048 dest_conv += 3 * sizeof(float);
4050 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4051 dest_conv += sizeof(float);
4055 if (DestFVF & WINED3DFVF_PSIZE) {
4056 dest_ptr += sizeof(DWORD);
4057 if(dest_conv) dest_conv += sizeof(DWORD);
4059 if (DestFVF & WINED3DFVF_NORMAL) {
4060 float *normal =
4061 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4062 /* AFAIK this should go into the lighting information */
4063 FIXME("Didn't expect the destination to have a normal\n");
4064 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4065 if(dest_conv) {
4066 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4070 if (DestFVF & WINED3DFVF_DIFFUSE) {
4071 DWORD *color_d =
4072 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4073 if(!color_d) {
4074 static BOOL warned = FALSE;
4076 if(!warned) {
4077 ERR("No diffuse color in source, but destination has one\n");
4078 warned = TRUE;
4081 *( (DWORD *) dest_ptr) = 0xffffffff;
4082 dest_ptr += sizeof(DWORD);
4084 if(dest_conv) {
4085 *( (DWORD *) dest_conv) = 0xffffffff;
4086 dest_conv += sizeof(DWORD);
4089 else {
4090 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4091 if(dest_conv) {
4092 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4093 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4094 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4095 dest_conv += sizeof(DWORD);
4100 if (DestFVF & WINED3DFVF_SPECULAR) {
4101 /* What's the color value in the feedback buffer? */
4102 DWORD *color_s =
4103 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4104 if(!color_s) {
4105 static BOOL warned = FALSE;
4107 if(!warned) {
4108 ERR("No specular color in source, but destination has one\n");
4109 warned = TRUE;
4112 *( (DWORD *) dest_ptr) = 0xFF000000;
4113 dest_ptr += sizeof(DWORD);
4115 if(dest_conv) {
4116 *( (DWORD *) dest_conv) = 0xFF000000;
4117 dest_conv += sizeof(DWORD);
4120 else {
4121 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4122 if(dest_conv) {
4123 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4124 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4125 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4126 dest_conv += sizeof(DWORD);
4131 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4132 float *tex_coord =
4133 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4134 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4135 if(!tex_coord) {
4136 ERR("No source texture, but destination requests one\n");
4137 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4138 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4140 else {
4141 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4142 if(dest_conv) {
4143 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4149 if(dest_conv) {
4150 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4151 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4152 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4153 dwCount * get_flexible_vertex_size(DestFVF),
4154 dest_conv_addr));
4155 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4156 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4159 LEAVE_GL();
4161 return WINED3D_OK;
4163 #undef copy_and_next
4165 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4167 WineDirect3DVertexStridedData strided;
4168 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4169 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4171 if(pVertexDecl) {
4172 ERR("Output vertex declaration not implemented yet\n");
4175 /* Need any context to write to the vbo. */
4176 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4178 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4179 * control the streamIsUP flag, thus restore it afterwards.
4181 This->stateBlock->streamIsUP = FALSE;
4182 memset(&strided, 0, sizeof(strided));
4183 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4184 This->stateBlock->streamIsUP = streamWasUP;
4186 if(vbo || SrcStartIndex) {
4187 unsigned int i;
4188 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4189 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4191 * Also get the start index in, but only loop over all elements if there's something to add at all.
4193 #define FIXSRC(type) \
4194 if(strided.u.s.type.VBO) { \
4195 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4196 strided.u.s.type.VBO = 0; \
4197 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4198 ENTER_GL(); \
4199 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4200 vb->vbo = 0; \
4201 LEAVE_GL(); \
4203 if(strided.u.s.type.lpData) { \
4204 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4206 FIXSRC(position);
4207 FIXSRC(blendWeights);
4208 FIXSRC(blendMatrixIndices);
4209 FIXSRC(normal);
4210 FIXSRC(pSize);
4211 FIXSRC(diffuse);
4212 FIXSRC(specular);
4213 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4214 FIXSRC(texCoords[i]);
4216 FIXSRC(position2);
4217 FIXSRC(normal2);
4218 FIXSRC(tangent);
4219 FIXSRC(binormal);
4220 FIXSRC(tessFactor);
4221 FIXSRC(fog);
4222 FIXSRC(depth);
4223 FIXSRC(sample);
4224 #undef FIXSRC
4227 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4230 /*****
4231 * Get / Set Texture Stage States
4232 * TODO: Verify against dx9 definitions
4233 *****/
4234 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4236 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4238 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4240 if (Stage >= MAX_TEXTURES) {
4241 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4242 return WINED3D_OK;
4245 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4246 This->updateStateBlock->textureState[Stage][Type] = Value;
4248 if (This->isRecordingState) {
4249 TRACE("Recording... not performing anything\n");
4250 return WINED3D_OK;
4253 /* Checked after the assignments to allow proper stateblock recording */
4254 if(oldValue == Value) {
4255 TRACE("App is setting the old value over, nothing to do\n");
4256 return WINED3D_OK;
4259 if(Stage > This->stateBlock->lowest_disabled_stage &&
4260 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4261 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4262 * Changes in other states are important on disabled stages too
4264 return WINED3D_OK;
4267 if(Type == WINED3DTSS_COLOROP) {
4268 int i;
4270 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4271 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4272 * they have to be disabled
4274 * The current stage is dirtified below.
4276 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4277 TRACE("Additionally dirtifying stage %d\n", i);
4278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4280 This->stateBlock->lowest_disabled_stage = Stage;
4281 TRACE("New lowest disabled: %d\n", Stage);
4282 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4283 /* Previously disabled stage enabled. Stages above it may need enabling
4284 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4285 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4287 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4290 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4291 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4292 break;
4294 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4297 This->stateBlock->lowest_disabled_stage = i;
4298 TRACE("New lowest disabled: %d\n", i);
4300 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4301 /* TODO: Built a stage -> texture unit mapping for register combiners */
4305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4307 return WINED3D_OK;
4310 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4312 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4313 *pValue = This->updateStateBlock->textureState[Stage][Type];
4314 return WINED3D_OK;
4317 /*****
4318 * Get / Set Texture
4319 *****/
4320 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4322 IWineD3DBaseTexture *oldTexture;
4324 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4326 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4327 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4330 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4331 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4332 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4335 oldTexture = This->updateStateBlock->textures[Stage];
4337 if(pTexture != NULL) {
4338 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4340 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4341 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4342 return WINED3DERR_INVALIDCALL;
4344 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4347 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4348 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4350 This->updateStateBlock->changed.textures[Stage] = TRUE;
4351 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4352 This->updateStateBlock->textures[Stage] = pTexture;
4354 /* Handle recording of state blocks */
4355 if (This->isRecordingState) {
4356 TRACE("Recording... not performing anything\n");
4357 return WINED3D_OK;
4360 if(oldTexture == pTexture) {
4361 TRACE("App is setting the same texture again, nothing to do\n");
4362 return WINED3D_OK;
4365 /** NOTE: MSDN says that setTexture increases the reference count,
4366 * and that the application must set the texture back to null (or have a leaky application),
4367 * This means we should pass the refcount up to the parent
4368 *******************************/
4369 if (NULL != This->updateStateBlock->textures[Stage]) {
4370 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4371 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4373 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4374 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4375 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4376 * so the COLOROP and ALPHAOP have to be dirtified.
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4381 if(bindCount == 1) {
4382 new->baseTexture.sampler = Stage;
4384 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4388 if (NULL != oldTexture) {
4389 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4390 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4392 IWineD3DBaseTexture_Release(oldTexture);
4393 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4398 if(bindCount && old->baseTexture.sampler == Stage) {
4399 int i;
4400 /* Have to do a search for the other sampler(s) where the texture is bound to
4401 * Shouldn't happen as long as apps bind a texture only to one stage
4403 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4404 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4405 if(This->updateStateBlock->textures[i] == oldTexture) {
4406 old->baseTexture.sampler = i;
4407 break;
4413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4415 return WINED3D_OK;
4418 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4421 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4423 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4424 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4427 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4428 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4429 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4432 *ppTexture=This->stateBlock->textures[Stage];
4433 if (*ppTexture)
4434 IWineD3DBaseTexture_AddRef(*ppTexture);
4436 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4438 return WINED3D_OK;
4441 /*****
4442 * Get Back Buffer
4443 *****/
4444 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4445 IWineD3DSurface **ppBackBuffer) {
4446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4447 IWineD3DSwapChain *swapChain;
4448 HRESULT hr;
4450 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4452 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4453 if (hr == WINED3D_OK) {
4454 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4455 IWineD3DSwapChain_Release(swapChain);
4456 } else {
4457 *ppBackBuffer = NULL;
4459 return hr;
4462 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4464 WARN("(%p) : stub, calling idirect3d for now\n", This);
4465 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4468 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4470 IWineD3DSwapChain *swapChain;
4471 HRESULT hr;
4473 if(iSwapChain > 0) {
4474 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4475 if (hr == WINED3D_OK) {
4476 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4477 IWineD3DSwapChain_Release(swapChain);
4478 } else {
4479 FIXME("(%p) Error getting display mode\n", This);
4481 } else {
4482 /* Don't read the real display mode,
4483 but return the stored mode instead. X11 can't change the color
4484 depth, and some apps are pretty angry if they SetDisplayMode from
4485 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4487 Also don't relay to the swapchain because with ddraw it's possible
4488 that there isn't a swapchain at all */
4489 pMode->Width = This->ddraw_width;
4490 pMode->Height = This->ddraw_height;
4491 pMode->Format = This->ddraw_format;
4492 pMode->RefreshRate = 0;
4493 hr = WINED3D_OK;
4496 return hr;
4499 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4501 TRACE("(%p)->(%p)\n", This, hWnd);
4503 if(This->ddraw_fullscreen) {
4504 if(This->ddraw_window && This->ddraw_window != hWnd) {
4505 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4507 if(hWnd && This->ddraw_window != hWnd) {
4508 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4512 This->ddraw_window = hWnd;
4513 return WINED3D_OK;
4516 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 TRACE("(%p)->(%p)\n", This, hWnd);
4520 *hWnd = This->ddraw_window;
4521 return WINED3D_OK;
4524 /*****
4525 * Stateblock related functions
4526 *****/
4528 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 IWineD3DStateBlockImpl *object;
4531 HRESULT temp_result;
4532 int i;
4534 TRACE("(%p)\n", This);
4536 if (This->isRecordingState) {
4537 return WINED3DERR_INVALIDCALL;
4540 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4541 if (NULL == object ) {
4542 FIXME("(%p)Error allocating memory for stateblock\n", This);
4543 return E_OUTOFMEMORY;
4545 TRACE("(%p) created object %p\n", This, object);
4546 object->wineD3DDevice= This;
4547 /** FIXME: object->parent = parent; **/
4548 object->parent = NULL;
4549 object->blockType = WINED3DSBT_RECORDED;
4550 object->ref = 1;
4551 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4553 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4554 list_init(&object->lightMap[i]);
4557 temp_result = allocate_shader_constants(object);
4558 if (WINED3D_OK != temp_result)
4559 return temp_result;
4561 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4562 This->updateStateBlock = object;
4563 This->isRecordingState = TRUE;
4565 TRACE("(%p) recording stateblock %p\n",This , object);
4566 return WINED3D_OK;
4569 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4571 unsigned int i, j;
4572 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4574 if (!This->isRecordingState) {
4575 FIXME("(%p) not recording! returning error\n", This);
4576 *ppStateBlock = NULL;
4577 return WINED3DERR_INVALIDCALL;
4580 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4581 if(object->changed.renderState[i]) {
4582 object->contained_render_states[object->num_contained_render_states] = i;
4583 object->num_contained_render_states++;
4586 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4587 if(object->changed.transform[i]) {
4588 object->contained_transform_states[object->num_contained_transform_states] = i;
4589 object->num_contained_transform_states++;
4592 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4593 if(object->changed.vertexShaderConstantsF[i]) {
4594 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4595 object->num_contained_vs_consts_f++;
4598 for(i = 0; i < MAX_CONST_I; i++) {
4599 if(object->changed.vertexShaderConstantsI[i]) {
4600 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4601 object->num_contained_vs_consts_i++;
4604 for(i = 0; i < MAX_CONST_B; i++) {
4605 if(object->changed.vertexShaderConstantsB[i]) {
4606 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4607 object->num_contained_vs_consts_b++;
4610 for(i = 0; i < MAX_CONST_I; i++) {
4611 if(object->changed.pixelShaderConstantsI[i]) {
4612 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4613 object->num_contained_ps_consts_i++;
4616 for(i = 0; i < MAX_CONST_B; i++) {
4617 if(object->changed.pixelShaderConstantsB[i]) {
4618 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4619 object->num_contained_ps_consts_b++;
4622 for(i = 0; i < MAX_TEXTURES; i++) {
4623 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4624 if(object->changed.textureState[i][j]) {
4625 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4626 object->contained_tss_states[object->num_contained_tss_states].state = j;
4627 object->num_contained_tss_states++;
4631 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4632 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4633 if(object->changed.samplerState[i][j]) {
4634 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4635 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4636 object->num_contained_sampler_states++;
4641 *ppStateBlock = (IWineD3DStateBlock*) object;
4642 This->isRecordingState = FALSE;
4643 This->updateStateBlock = This->stateBlock;
4644 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4645 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4646 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4647 return WINED3D_OK;
4650 /*****
4651 * Scene related functions
4652 *****/
4653 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4654 /* At the moment we have no need for any functionality at the beginning
4655 of a scene */
4656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 TRACE("(%p)\n", This);
4659 if(This->inScene) {
4660 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4661 return WINED3DERR_INVALIDCALL;
4663 This->inScene = TRUE;
4664 return WINED3D_OK;
4667 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 TRACE("(%p)\n", This);
4671 if(!This->inScene) {
4672 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4673 return WINED3DERR_INVALIDCALL;
4676 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4677 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4678 ENTER_GL();
4679 glFlush();
4680 checkGLcall("glFlush");
4681 LEAVE_GL();
4683 This->inScene = FALSE;
4684 return WINED3D_OK;
4687 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4688 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4689 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 IWineD3DSwapChain *swapChain = NULL;
4692 int i;
4693 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4695 TRACE("(%p) Presenting the frame\n", This);
4697 for(i = 0 ; i < swapchains ; i ++) {
4699 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4700 TRACE("presentinng chain %d, %p\n", i, swapChain);
4701 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4702 IWineD3DSwapChain_Release(swapChain);
4705 return WINED3D_OK;
4708 /* Not called from the VTable (internal subroutine) */
4709 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4710 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4711 float Z, DWORD Stencil) {
4712 GLbitfield glMask = 0;
4713 unsigned int i;
4714 WINED3DRECT curRect;
4715 RECT vp_rect;
4716 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4717 UINT drawable_width, drawable_height;
4718 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4720 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4721 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4722 * for the cleared parts, and the untouched parts.
4724 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4725 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4726 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4727 * checking all this if the dest surface is in the drawable anyway.
4729 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4730 while(1) {
4731 if(vp->X != 0 || vp->Y != 0 ||
4732 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4733 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4734 break;
4736 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4737 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4738 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4739 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4740 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4741 break;
4743 if(Count > 0 && pRects && (
4744 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4745 pRects[0].x2 < target->currentDesc.Width ||
4746 pRects[0].y2 < target->currentDesc.Height)) {
4747 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4748 break;
4750 break;
4754 target->get_drawable_size(target, &drawable_width, &drawable_height);
4756 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4757 ENTER_GL();
4759 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4760 apply_fbo_state((IWineD3DDevice *) This);
4763 /* Only set the values up once, as they are not changing */
4764 if (Flags & WINED3DCLEAR_STENCIL) {
4765 glClearStencil(Stencil);
4766 checkGLcall("glClearStencil");
4767 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4768 glStencilMask(0xFFFFFFFF);
4771 if (Flags & WINED3DCLEAR_ZBUFFER) {
4772 glDepthMask(GL_TRUE);
4773 glClearDepth(Z);
4774 checkGLcall("glClearDepth");
4775 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4778 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4779 if(vp->X != 0 || vp->Y != 0 ||
4780 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4781 depth_copy((IWineD3DDevice *) This);
4783 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4784 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4785 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4786 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4787 depth_copy((IWineD3DDevice *) This);
4789 else if(Count > 0 && pRects && (
4790 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4791 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4792 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4793 depth_copy((IWineD3DDevice *) This);
4796 This->depth_copy_state = WINED3D_DCS_INITIAL;
4799 if (Flags & WINED3DCLEAR_TARGET) {
4800 TRACE("Clearing screen with glClear to color %x\n", Color);
4801 glClearColor(D3DCOLOR_R(Color),
4802 D3DCOLOR_G(Color),
4803 D3DCOLOR_B(Color),
4804 D3DCOLOR_A(Color));
4805 checkGLcall("glClearColor");
4807 /* Clear ALL colors! */
4808 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4809 glMask = glMask | GL_COLOR_BUFFER_BIT;
4812 vp_rect.left = vp->X;
4813 vp_rect.top = vp->Y;
4814 vp_rect.right = vp->X + vp->Width;
4815 vp_rect.bottom = vp->Y + vp->Height;
4816 if (!(Count > 0 && pRects)) {
4817 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4818 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4820 if(This->render_offscreen) {
4821 glScissor(vp_rect.left, vp_rect.top,
4822 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4823 } else {
4824 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4825 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4827 checkGLcall("glScissor");
4828 glClear(glMask);
4829 checkGLcall("glClear");
4830 } else {
4831 /* Now process each rect in turn */
4832 for (i = 0; i < Count; i++) {
4833 /* Note gl uses lower left, width/height */
4834 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4835 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4836 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4838 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4839 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4840 curRect.x1, (target->currentDesc.Height - curRect.y2),
4841 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4843 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4844 * The rectangle is not cleared, no error is returned, but further rectanlges are
4845 * still cleared if they are valid
4847 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4848 TRACE("Rectangle with negative dimensions, ignoring\n");
4849 continue;
4852 if(This->render_offscreen) {
4853 glScissor(curRect.x1, curRect.y1,
4854 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4855 } else {
4856 glScissor(curRect.x1, drawable_height - curRect.y2,
4857 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4859 checkGLcall("glScissor");
4861 glClear(glMask);
4862 checkGLcall("glClear");
4866 /* Restore the old values (why..?) */
4867 if (Flags & WINED3DCLEAR_STENCIL) {
4868 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4870 if (Flags & WINED3DCLEAR_TARGET) {
4871 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4872 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4873 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4874 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4875 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4877 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4878 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4880 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4881 /* TODO: Move the fbo logic into ModifyLocation() */
4882 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4883 target->Flags |= SFLAG_INTEXTURE;
4886 LEAVE_GL();
4888 return WINED3D_OK;
4891 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4892 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4894 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4896 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4897 Count, pRects, Flags, Color, Z, Stencil);
4899 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4900 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4901 /* TODO: What about depth stencil buffers without stencil bits? */
4902 return WINED3DERR_INVALIDCALL;
4905 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4908 /*****
4909 * Drawing functions
4910 *****/
4911 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4912 UINT PrimitiveCount) {
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4916 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4917 debug_d3dprimitivetype(PrimitiveType),
4918 StartVertex, PrimitiveCount);
4920 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4921 if(This->stateBlock->streamIsUP) {
4922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4923 This->stateBlock->streamIsUP = FALSE;
4926 if(This->stateBlock->loadBaseVertexIndex != 0) {
4927 This->stateBlock->loadBaseVertexIndex = 0;
4928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4930 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4931 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4932 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4933 return WINED3D_OK;
4936 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4937 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4938 WINED3DPRIMITIVETYPE PrimitiveType,
4939 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4942 UINT idxStride = 2;
4943 IWineD3DIndexBuffer *pIB;
4944 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4945 GLuint vbo;
4947 pIB = This->stateBlock->pIndexData;
4948 if (!pIB) {
4949 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4950 * without an index buffer set. (The first time at least...)
4951 * D3D8 simply dies, but I doubt it can do much harm to return
4952 * D3DERR_INVALIDCALL there as well. */
4953 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4954 return WINED3DERR_INVALIDCALL;
4957 if(This->stateBlock->streamIsUP) {
4958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4959 This->stateBlock->streamIsUP = FALSE;
4961 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4963 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4964 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4965 minIndex, NumVertices, startIndex, primCount);
4967 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4968 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4969 idxStride = 2;
4970 } else {
4971 idxStride = 4;
4974 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4975 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4979 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4980 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4982 return WINED3D_OK;
4985 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4986 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4987 UINT VertexStreamZeroStride) {
4988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4989 IWineD3DVertexBuffer *vb;
4991 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4992 debug_d3dprimitivetype(PrimitiveType),
4993 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4995 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4996 vb = This->stateBlock->streamSource[0];
4997 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4998 if(vb) IWineD3DVertexBuffer_Release(vb);
4999 This->stateBlock->streamOffset[0] = 0;
5000 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5001 This->stateBlock->streamIsUP = TRUE;
5002 This->stateBlock->loadBaseVertexIndex = 0;
5004 /* TODO: Only mark dirty if drawing from a different UP address */
5005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5007 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5008 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5010 /* MSDN specifies stream zero settings must be set to NULL */
5011 This->stateBlock->streamStride[0] = 0;
5012 This->stateBlock->streamSource[0] = NULL;
5014 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5015 * the new stream sources or use UP drawing again
5017 return WINED3D_OK;
5020 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5021 UINT MinVertexIndex, UINT NumVertices,
5022 UINT PrimitiveCount, CONST void* pIndexData,
5023 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5024 UINT VertexStreamZeroStride) {
5025 int idxStride;
5026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 IWineD3DVertexBuffer *vb;
5028 IWineD3DIndexBuffer *ib;
5030 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5031 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5032 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5033 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5035 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5036 idxStride = 2;
5037 } else {
5038 idxStride = 4;
5041 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5042 vb = This->stateBlock->streamSource[0];
5043 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5044 if(vb) IWineD3DVertexBuffer_Release(vb);
5045 This->stateBlock->streamIsUP = TRUE;
5046 This->stateBlock->streamOffset[0] = 0;
5047 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5049 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5050 This->stateBlock->baseVertexIndex = 0;
5051 This->stateBlock->loadBaseVertexIndex = 0;
5052 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5056 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5058 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5059 This->stateBlock->streamSource[0] = NULL;
5060 This->stateBlock->streamStride[0] = 0;
5061 ib = This->stateBlock->pIndexData;
5062 if(ib) {
5063 IWineD3DIndexBuffer_Release(ib);
5064 This->stateBlock->pIndexData = NULL;
5066 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5067 * SetStreamSource to specify a vertex buffer
5070 return WINED3D_OK;
5073 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5076 /* Mark the state dirty until we have nicer tracking
5077 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5078 * that value.
5080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5082 This->stateBlock->baseVertexIndex = 0;
5083 This->up_strided = DrawPrimStrideData;
5084 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5085 This->up_strided = NULL;
5086 return WINED3D_OK;
5089 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5091 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5093 /* Mark the state dirty until we have nicer tracking
5094 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5095 * that value.
5097 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5099 This->stateBlock->streamIsUP = TRUE;
5100 This->stateBlock->baseVertexIndex = 0;
5101 This->up_strided = DrawPrimStrideData;
5102 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5103 This->up_strided = NULL;
5104 return WINED3D_OK;
5107 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5108 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5109 * not callable by the app directly no parameter validation checks are needed here.
5111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5112 WINED3DLOCKED_BOX src;
5113 WINED3DLOCKED_BOX dst;
5114 HRESULT hr;
5115 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5117 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5118 * dirtification to improve loading performance.
5120 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5121 if(FAILED(hr)) return hr;
5122 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5123 if(FAILED(hr)) {
5124 IWineD3DVolume_UnlockBox(pSourceVolume);
5125 return hr;
5128 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5130 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5131 if(FAILED(hr)) {
5132 IWineD3DVolume_UnlockBox(pSourceVolume);
5133 } else {
5134 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5136 return hr;
5139 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5140 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 HRESULT hr = WINED3D_OK;
5143 WINED3DRESOURCETYPE sourceType;
5144 WINED3DRESOURCETYPE destinationType;
5145 int i ,levels;
5147 /* TODO: think about moving the code into IWineD3DBaseTexture */
5149 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5151 /* verify that the source and destination textures aren't NULL */
5152 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5153 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5154 This, pSourceTexture, pDestinationTexture);
5155 hr = WINED3DERR_INVALIDCALL;
5158 if (pSourceTexture == pDestinationTexture) {
5159 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5160 This, pSourceTexture, pDestinationTexture);
5161 hr = WINED3DERR_INVALIDCALL;
5163 /* Verify that the source and destination textures are the same type */
5164 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5165 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5167 if (sourceType != destinationType) {
5168 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5169 This);
5170 hr = WINED3DERR_INVALIDCALL;
5173 /* check that both textures have the identical numbers of levels */
5174 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5175 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5176 hr = WINED3DERR_INVALIDCALL;
5179 if (WINED3D_OK == hr) {
5181 /* Make sure that the destination texture is loaded */
5182 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5184 /* Update every surface level of the texture */
5185 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5187 switch (sourceType) {
5188 case WINED3DRTYPE_TEXTURE:
5190 IWineD3DSurface *srcSurface;
5191 IWineD3DSurface *destSurface;
5193 for (i = 0 ; i < levels ; ++i) {
5194 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5195 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5196 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5197 IWineD3DSurface_Release(srcSurface);
5198 IWineD3DSurface_Release(destSurface);
5199 if (WINED3D_OK != hr) {
5200 WARN("(%p) : Call to update surface failed\n", This);
5201 return hr;
5205 break;
5206 case WINED3DRTYPE_CUBETEXTURE:
5208 IWineD3DSurface *srcSurface;
5209 IWineD3DSurface *destSurface;
5210 WINED3DCUBEMAP_FACES faceType;
5212 for (i = 0 ; i < levels ; ++i) {
5213 /* Update each cube face */
5214 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5215 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5216 if (WINED3D_OK != hr) {
5217 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5218 } else {
5219 TRACE("Got srcSurface %p\n", srcSurface);
5221 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5222 if (WINED3D_OK != hr) {
5223 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5224 } else {
5225 TRACE("Got desrSurface %p\n", destSurface);
5227 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5228 IWineD3DSurface_Release(srcSurface);
5229 IWineD3DSurface_Release(destSurface);
5230 if (WINED3D_OK != hr) {
5231 WARN("(%p) : Call to update surface failed\n", This);
5232 return hr;
5237 break;
5239 case WINED3DRTYPE_VOLUMETEXTURE:
5241 IWineD3DVolume *srcVolume = NULL;
5242 IWineD3DVolume *destVolume = NULL;
5244 for (i = 0 ; i < levels ; ++i) {
5245 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5246 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5247 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5248 IWineD3DVolume_Release(srcVolume);
5249 IWineD3DVolume_Release(destVolume);
5250 if (WINED3D_OK != hr) {
5251 WARN("(%p) : Call to update volume failed\n", This);
5252 return hr;
5256 break;
5258 default:
5259 FIXME("(%p) : Unsupported source and destination type\n", This);
5260 hr = WINED3DERR_INVALIDCALL;
5264 return hr;
5267 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5268 IWineD3DSwapChain *swapChain;
5269 HRESULT hr;
5270 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5271 if(hr == WINED3D_OK) {
5272 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5273 IWineD3DSwapChain_Release(swapChain);
5275 return hr;
5278 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 /* return a sensible default */
5281 *pNumPasses = 1;
5282 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5283 FIXME("(%p) : stub\n", This);
5284 return WINED3D_OK;
5287 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 int j;
5290 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5291 if (PaletteNumber >= MAX_PALETTES) {
5292 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5293 return WINED3DERR_INVALIDCALL;
5295 for (j = 0; j < 256; ++j) {
5296 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5297 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5298 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5299 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5301 TRACE("(%p) : returning\n", This);
5302 return WINED3D_OK;
5305 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5307 int j;
5308 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5309 if (PaletteNumber >= MAX_PALETTES) {
5310 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5311 return WINED3DERR_INVALIDCALL;
5313 for (j = 0; j < 256; ++j) {
5314 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5315 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5316 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5317 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5319 TRACE("(%p) : returning\n", This);
5320 return WINED3D_OK;
5323 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5325 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5326 if (PaletteNumber >= MAX_PALETTES) {
5327 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5328 return WINED3DERR_INVALIDCALL;
5330 /*TODO: stateblocks */
5331 This->currentPalette = PaletteNumber;
5332 TRACE("(%p) : returning\n", This);
5333 return WINED3D_OK;
5336 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 if (PaletteNumber == NULL) {
5339 WARN("(%p) : returning Invalid Call\n", This);
5340 return WINED3DERR_INVALIDCALL;
5342 /*TODO: stateblocks */
5343 *PaletteNumber = This->currentPalette;
5344 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5345 return WINED3D_OK;
5348 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 static BOOL showFixmes = TRUE;
5351 if (showFixmes) {
5352 FIXME("(%p) : stub\n", This);
5353 showFixmes = FALSE;
5356 This->softwareVertexProcessing = bSoftware;
5357 return WINED3D_OK;
5361 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5363 static BOOL showFixmes = TRUE;
5364 if (showFixmes) {
5365 FIXME("(%p) : stub\n", This);
5366 showFixmes = FALSE;
5368 return This->softwareVertexProcessing;
5372 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 IWineD3DSwapChain *swapChain;
5375 HRESULT hr;
5377 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5379 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5380 if(hr == WINED3D_OK){
5381 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5382 IWineD3DSwapChain_Release(swapChain);
5383 }else{
5384 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5386 return hr;
5390 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5392 static BOOL showfixmes = TRUE;
5393 if(nSegments != 0.0f) {
5394 if( showfixmes) {
5395 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5396 showfixmes = FALSE;
5399 return WINED3D_OK;
5402 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 static BOOL showfixmes = TRUE;
5405 if( showfixmes) {
5406 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5407 showfixmes = FALSE;
5409 return 0.0f;
5412 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5414 /** TODO: remove casts to IWineD3DSurfaceImpl
5415 * NOTE: move code to surface to accomplish this
5416 ****************************************/
5417 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5418 int srcWidth, srcHeight;
5419 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5420 WINED3DFORMAT destFormat, srcFormat;
5421 UINT destSize;
5422 int srcLeft, destLeft, destTop;
5423 WINED3DPOOL srcPool, destPool;
5424 int offset = 0;
5425 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5426 glDescriptor *glDescription = NULL;
5427 GLenum dummy;
5428 int bpp;
5429 CONVERT_TYPES convert = NO_CONVERSION;
5431 WINED3DSURFACE_DESC winedesc;
5433 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5434 memset(&winedesc, 0, sizeof(winedesc));
5435 winedesc.Width = &srcSurfaceWidth;
5436 winedesc.Height = &srcSurfaceHeight;
5437 winedesc.Pool = &srcPool;
5438 winedesc.Format = &srcFormat;
5440 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5442 winedesc.Width = &destSurfaceWidth;
5443 winedesc.Height = &destSurfaceHeight;
5444 winedesc.Pool = &destPool;
5445 winedesc.Format = &destFormat;
5446 winedesc.Size = &destSize;
5448 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5450 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5451 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5452 return WINED3DERR_INVALIDCALL;
5455 /* This call loads the opengl surface directly, instead of copying the surface to the
5456 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5457 * copy in sysmem and use regular surface loading.
5459 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5460 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5461 if(convert != NO_CONVERSION) {
5462 return IWineD3DSurface_BltFast(pDestinationSurface,
5463 pDestPoint ? pDestPoint->x : 0,
5464 pDestPoint ? pDestPoint->y : 0,
5465 pSourceSurface, (RECT *) pSourceRect, 0);
5468 if (destFormat == WINED3DFMT_UNKNOWN) {
5469 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5470 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5472 /* Get the update surface description */
5473 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5476 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5478 ENTER_GL();
5480 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5481 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5482 checkGLcall("glActiveTextureARB");
5485 /* Make sure the surface is loaded and up to date */
5486 IWineD3DSurface_PreLoad(pDestinationSurface);
5488 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5490 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5491 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5492 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5493 srcLeft = pSourceRect ? pSourceRect->left : 0;
5494 destLeft = pDestPoint ? pDestPoint->x : 0;
5495 destTop = pDestPoint ? pDestPoint->y : 0;
5498 /* This function doesn't support compressed textures
5499 the pitch is just bytesPerPixel * width */
5500 if(srcWidth != srcSurfaceWidth || srcLeft ){
5501 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5502 offset += srcLeft * pSrcSurface->bytesPerPixel;
5503 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5505 /* TODO DXT formats */
5507 if(pSourceRect != NULL && pSourceRect->top != 0){
5508 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5510 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5511 ,This
5512 ,glDescription->level
5513 ,destLeft
5514 ,destTop
5515 ,srcWidth
5516 ,srcHeight
5517 ,glDescription->glFormat
5518 ,glDescription->glType
5519 ,IWineD3DSurface_GetData(pSourceSurface)
5522 /* Sanity check */
5523 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5525 /* need to lock the surface to get the data */
5526 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5529 /* TODO: Cube and volume support */
5530 if(rowoffset != 0){
5531 /* not a whole row so we have to do it a line at a time */
5532 int j;
5534 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5535 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5537 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5539 glTexSubImage2D(glDescription->target
5540 ,glDescription->level
5541 ,destLeft
5543 ,srcWidth
5545 ,glDescription->glFormat
5546 ,glDescription->glType
5547 ,data /* could be quicker using */
5549 data += rowoffset;
5552 } else { /* Full width, so just write out the whole texture */
5554 if (WINED3DFMT_DXT1 == destFormat ||
5555 WINED3DFMT_DXT2 == destFormat ||
5556 WINED3DFMT_DXT3 == destFormat ||
5557 WINED3DFMT_DXT4 == destFormat ||
5558 WINED3DFMT_DXT5 == destFormat) {
5559 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5560 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5561 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5562 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5563 } if (destFormat != srcFormat) {
5564 FIXME("Updating mixed format compressed texture is not curretly support\n");
5565 } else {
5566 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5567 glDescription->level,
5568 glDescription->glFormatInternal,
5569 srcWidth,
5570 srcHeight,
5572 destSize,
5573 IWineD3DSurface_GetData(pSourceSurface));
5575 } else {
5576 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5580 } else {
5581 glTexSubImage2D(glDescription->target
5582 ,glDescription->level
5583 ,destLeft
5584 ,destTop
5585 ,srcWidth
5586 ,srcHeight
5587 ,glDescription->glFormat
5588 ,glDescription->glType
5589 ,IWineD3DSurface_GetData(pSourceSurface)
5593 checkGLcall("glTexSubImage2D");
5595 LEAVE_GL();
5597 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5600 return WINED3D_OK;
5603 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5605 struct WineD3DRectPatch *patch;
5606 unsigned int i;
5607 struct list *e;
5608 BOOL found;
5609 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5611 if(!(Handle || pRectPatchInfo)) {
5612 /* TODO: Write a test for the return value, thus the FIXME */
5613 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5614 return WINED3DERR_INVALIDCALL;
5617 if(Handle) {
5618 i = PATCHMAP_HASHFUNC(Handle);
5619 found = FALSE;
5620 LIST_FOR_EACH(e, &This->patches[i]) {
5621 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5622 if(patch->Handle == Handle) {
5623 found = TRUE;
5624 break;
5628 if(!found) {
5629 TRACE("Patch does not exist. Creating a new one\n");
5630 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5631 patch->Handle = Handle;
5632 list_add_head(&This->patches[i], &patch->entry);
5633 } else {
5634 TRACE("Found existing patch %p\n", patch);
5636 } else {
5637 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5638 * attributes we have to tesselate, read back, and draw. This needs a patch
5639 * management structure instance. Create one.
5641 * A possible improvement is to check if a vertex shader is used, and if not directly
5642 * draw the patch.
5644 FIXME("Drawing an uncached patch. This is slow\n");
5645 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5648 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5649 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5650 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5651 HRESULT hr;
5652 TRACE("Tesselation density or patch info changed, retesselating\n");
5654 if(pRectPatchInfo) {
5655 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5657 patch->numSegs[0] = pNumSegs[0];
5658 patch->numSegs[1] = pNumSegs[1];
5659 patch->numSegs[2] = pNumSegs[2];
5660 patch->numSegs[3] = pNumSegs[3];
5662 hr = tesselate_rectpatch(This, patch);
5663 if(FAILED(hr)) {
5664 WARN("Patch tesselation failed\n");
5666 /* Do not release the handle to store the params of the patch */
5667 if(!Handle) {
5668 HeapFree(GetProcessHeap(), 0, patch);
5670 return hr;
5674 This->currentPatch = patch;
5675 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5676 This->currentPatch = NULL;
5678 /* Destroy uncached patches */
5679 if(!Handle) {
5680 HeapFree(GetProcessHeap(), 0, patch->mem);
5681 HeapFree(GetProcessHeap(), 0, patch);
5683 return WINED3D_OK;
5686 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5687 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5690 FIXME("(%p) : Stub\n", This);
5691 return WINED3D_OK;
5694 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5696 int i;
5697 struct WineD3DRectPatch *patch;
5698 struct list *e;
5699 TRACE("(%p) Handle(%d)\n", This, Handle);
5701 i = PATCHMAP_HASHFUNC(Handle);
5702 LIST_FOR_EACH(e, &This->patches[i]) {
5703 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5704 if(patch->Handle == Handle) {
5705 TRACE("Deleting patch %p\n", patch);
5706 list_remove(&patch->entry);
5707 HeapFree(GetProcessHeap(), 0, patch->mem);
5708 HeapFree(GetProcessHeap(), 0, patch);
5709 return WINED3D_OK;
5713 /* TODO: Write a test for the return value */
5714 FIXME("Attempt to destroy nonexistent patch\n");
5715 return WINED3DERR_INVALIDCALL;
5718 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5719 HRESULT hr;
5720 IWineD3DSwapChain *swapchain;
5722 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5723 if (SUCCEEDED(hr)) {
5724 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5725 return swapchain;
5728 return NULL;
5731 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5734 if (!*fbo) {
5735 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5736 checkGLcall("glGenFramebuffersEXT()");
5738 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5739 checkGLcall("glBindFramebuffer()");
5742 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5743 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5744 IWineD3DBaseTextureImpl *texture_impl;
5745 GLenum texttarget, target;
5746 GLint old_binding;
5748 texttarget = surface_impl->glDescription.target;
5749 if(texttarget == GL_TEXTURE_2D) {
5750 target = GL_TEXTURE_2D;
5751 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5752 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5753 target = GL_TEXTURE_RECTANGLE_ARB;
5754 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5755 } else {
5756 target = GL_TEXTURE_CUBE_MAP_ARB;
5757 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5760 IWineD3DSurface_PreLoad(surface);
5762 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5763 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5764 glBindTexture(target, old_binding);
5766 /* Update base texture states array */
5767 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5768 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5769 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5770 if (texture_impl->baseTexture.bindCount) {
5771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5774 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5777 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5778 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5780 checkGLcall("attach_surface_fbo");
5783 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5785 IWineD3DSwapChain *swapchain;
5787 swapchain = get_swapchain(surface);
5788 if (swapchain) {
5789 GLenum buffer;
5791 TRACE("Surface %p is onscreen\n", surface);
5793 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5794 buffer = surface_get_gl_buffer(surface, swapchain);
5795 glDrawBuffer(buffer);
5796 checkGLcall("glDrawBuffer()");
5797 } else {
5798 TRACE("Surface %p is offscreen\n", surface);
5799 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5800 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5803 if (rect) {
5804 glEnable(GL_SCISSOR_TEST);
5805 if(!swapchain) {
5806 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5807 } else {
5808 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5809 rect->x2 - rect->x1, rect->y2 - rect->y1);
5811 checkGLcall("glScissor");
5812 } else {
5813 glDisable(GL_SCISSOR_TEST);
5815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5817 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5820 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5821 glClear(GL_COLOR_BUFFER_BIT);
5822 checkGLcall("glClear");
5824 if (This->render_offscreen) {
5825 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5826 } else {
5827 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5828 checkGLcall("glBindFramebuffer()");
5831 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5832 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5833 glDrawBuffer(GL_BACK);
5834 checkGLcall("glDrawBuffer()");
5838 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5839 unsigned int r, g, b, a;
5840 DWORD ret;
5842 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5843 destfmt == WINED3DFMT_R8G8B8)
5844 return color;
5846 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5848 a = (color & 0xff000000) >> 24;
5849 r = (color & 0x00ff0000) >> 16;
5850 g = (color & 0x0000ff00) >> 8;
5851 b = (color & 0x000000ff) >> 0;
5853 switch(destfmt)
5855 case WINED3DFMT_R5G6B5:
5856 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5857 r = (r * 32) / 256;
5858 g = (g * 64) / 256;
5859 b = (b * 32) / 256;
5860 ret = r << 11;
5861 ret |= g << 5;
5862 ret |= b;
5863 TRACE("Returning %08x\n", ret);
5864 return ret;
5866 case WINED3DFMT_X1R5G5B5:
5867 case WINED3DFMT_A1R5G5B5:
5868 a = (a * 2) / 256;
5869 r = (r * 32) / 256;
5870 g = (g * 32) / 256;
5871 b = (b * 32) / 256;
5872 ret = a << 15;
5873 ret |= r << 10;
5874 ret |= g << 5;
5875 ret |= b << 0;
5876 TRACE("Returning %08x\n", ret);
5877 return ret;
5879 case WINED3DFMT_A8:
5880 TRACE("Returning %08x\n", a);
5881 return a;
5883 case WINED3DFMT_X4R4G4B4:
5884 case WINED3DFMT_A4R4G4B4:
5885 a = (a * 16) / 256;
5886 r = (r * 16) / 256;
5887 g = (g * 16) / 256;
5888 b = (b * 16) / 256;
5889 ret = a << 12;
5890 ret |= r << 8;
5891 ret |= g << 4;
5892 ret |= b << 0;
5893 TRACE("Returning %08x\n", ret);
5894 return ret;
5896 case WINED3DFMT_R3G3B2:
5897 r = (r * 8) / 256;
5898 g = (g * 8) / 256;
5899 b = (b * 4) / 256;
5900 ret = r << 5;
5901 ret |= g << 2;
5902 ret |= b << 0;
5903 TRACE("Returning %08x\n", ret);
5904 return ret;
5906 case WINED3DFMT_X8B8G8R8:
5907 case WINED3DFMT_A8B8G8R8:
5908 ret = a << 24;
5909 ret |= b << 16;
5910 ret |= g << 8;
5911 ret |= r << 0;
5912 TRACE("Returning %08x\n", ret);
5913 return ret;
5915 case WINED3DFMT_A2R10G10B10:
5916 a = (a * 4) / 256;
5917 r = (r * 1024) / 256;
5918 g = (g * 1024) / 256;
5919 b = (b * 1024) / 256;
5920 ret = a << 30;
5921 ret |= r << 20;
5922 ret |= g << 10;
5923 ret |= b << 0;
5924 TRACE("Returning %08x\n", ret);
5925 return ret;
5927 case WINED3DFMT_A2B10G10R10:
5928 a = (a * 4) / 256;
5929 r = (r * 1024) / 256;
5930 g = (g * 1024) / 256;
5931 b = (b * 1024) / 256;
5932 ret = a << 30;
5933 ret |= b << 20;
5934 ret |= g << 10;
5935 ret |= r << 0;
5936 TRACE("Returning %08x\n", ret);
5937 return ret;
5939 default:
5940 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5941 return 0;
5945 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5947 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5948 WINEDDBLTFX BltFx;
5949 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5951 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5952 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5953 return WINED3DERR_INVALIDCALL;
5956 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5957 color_fill_fbo(iface, pSurface, pRect, color);
5958 return WINED3D_OK;
5959 } else {
5960 /* Just forward this to the DirectDraw blitting engine */
5961 memset(&BltFx, 0, sizeof(BltFx));
5962 BltFx.dwSize = sizeof(BltFx);
5963 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5964 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5968 /* rendertarget and depth stencil functions */
5969 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5972 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5973 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5974 return WINED3DERR_INVALIDCALL;
5977 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5978 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5979 /* Note inc ref on returned surface */
5980 if(*ppRenderTarget != NULL)
5981 IWineD3DSurface_AddRef(*ppRenderTarget);
5982 return WINED3D_OK;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5987 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5988 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5989 IWineD3DSwapChainImpl *Swapchain;
5990 HRESULT hr;
5992 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5994 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5995 if(hr != WINED3D_OK) {
5996 ERR("Can't get the swapchain\n");
5997 return hr;
6000 /* Make sure to release the swapchain */
6001 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6003 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6004 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6005 return WINED3DERR_INVALIDCALL;
6007 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6008 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6009 return WINED3DERR_INVALIDCALL;
6012 if(Swapchain->frontBuffer != Front) {
6013 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6015 if(Swapchain->frontBuffer)
6016 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6017 Swapchain->frontBuffer = Front;
6019 if(Swapchain->frontBuffer) {
6020 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6024 if(Back && !Swapchain->backBuffer) {
6025 /* We need memory for the back buffer array - only one back buffer this way */
6026 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6027 if(!Swapchain->backBuffer) {
6028 ERR("Out of memory\n");
6029 return E_OUTOFMEMORY;
6033 if(Swapchain->backBuffer[0] != Back) {
6034 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6036 /* What to do about the context here in the case of multithreading? Not sure.
6037 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6039 ENTER_GL();
6040 if(!Swapchain->backBuffer[0]) {
6041 /* GL was told to draw to the front buffer at creation,
6042 * undo that
6044 glDrawBuffer(GL_BACK);
6045 checkGLcall("glDrawBuffer(GL_BACK)");
6046 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6047 Swapchain->presentParms.BackBufferCount = 1;
6048 } else if (!Back) {
6049 /* That makes problems - disable for now */
6050 /* glDrawBuffer(GL_FRONT); */
6051 checkGLcall("glDrawBuffer(GL_FRONT)");
6052 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6053 Swapchain->presentParms.BackBufferCount = 0;
6055 LEAVE_GL();
6057 if(Swapchain->backBuffer[0])
6058 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6059 Swapchain->backBuffer[0] = Back;
6061 if(Swapchain->backBuffer[0]) {
6062 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6063 } else {
6064 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6065 Swapchain->backBuffer = NULL;
6070 return WINED3D_OK;
6073 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6075 *ppZStencilSurface = This->stencilBufferTarget;
6076 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6078 if(*ppZStencilSurface != NULL) {
6079 /* Note inc ref on returned surface */
6080 IWineD3DSurface_AddRef(*ppZStencilSurface);
6081 return WINED3D_OK;
6082 } else {
6083 return WINED3DERR_NOTFOUND;
6087 /* TODO: Handle stencil attachments */
6088 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6090 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6092 TRACE("Set depth stencil to %p\n", depth_stencil);
6094 if (depth_stencil_impl) {
6095 if (depth_stencil_impl->current_renderbuffer) {
6096 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6097 checkGLcall("glFramebufferRenderbufferEXT()");
6098 } else {
6099 IWineD3DBaseTextureImpl *texture_impl;
6100 GLenum texttarget, target;
6101 GLint old_binding = 0;
6103 texttarget = depth_stencil_impl->glDescription.target;
6104 if(texttarget == GL_TEXTURE_2D) {
6105 target = GL_TEXTURE_2D;
6106 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6107 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6108 target = GL_TEXTURE_RECTANGLE_ARB;
6109 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6110 } else {
6111 target = GL_TEXTURE_CUBE_MAP_ARB;
6112 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6115 IWineD3DSurface_PreLoad(depth_stencil);
6117 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6118 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6119 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6120 glBindTexture(target, old_binding);
6122 /* Update base texture states array */
6123 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6124 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6125 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6126 if (texture_impl->baseTexture.bindCount) {
6127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6130 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6133 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6134 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6135 checkGLcall("glFramebufferTexture2DEXT()");
6137 } else {
6138 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6139 checkGLcall("glFramebufferTexture2DEXT()");
6143 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6145 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6147 TRACE("Set render target %u to %p\n", idx, render_target);
6149 if (rtimpl) {
6150 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6151 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6152 } else {
6153 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6154 checkGLcall("glFramebufferTexture2DEXT()");
6156 This->draw_buffers[idx] = GL_NONE;
6160 static void check_fbo_status(IWineD3DDevice *iface) {
6161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6162 GLenum status;
6164 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6165 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6166 TRACE("FBO complete\n");
6167 } else {
6168 IWineD3DSurfaceImpl *attachment;
6169 int i;
6170 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6172 /* Dump the FBO attachments */
6173 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6174 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6175 if (attachment) {
6176 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6177 attachment->pow2Width, attachment->pow2Height);
6180 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6181 if (attachment) {
6182 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6183 attachment->pow2Width, attachment->pow2Height);
6188 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6190 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6191 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6193 if (!ds_impl) return FALSE;
6195 if (ds_impl->current_renderbuffer) {
6196 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6197 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6200 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6201 rt_impl->pow2Height != ds_impl->pow2Height);
6204 void apply_fbo_state(IWineD3DDevice *iface) {
6205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6206 unsigned int i;
6208 if (This->render_offscreen) {
6209 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6211 /* Apply render targets */
6212 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6213 IWineD3DSurface *render_target = This->render_targets[i];
6214 if (This->fbo_color_attachments[i] != render_target) {
6215 set_render_target_fbo(iface, i, render_target);
6216 This->fbo_color_attachments[i] = render_target;
6220 /* Apply depth targets */
6221 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6222 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6223 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6225 if (This->stencilBufferTarget) {
6226 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6228 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6229 This->fbo_depth_attachment = This->stencilBufferTarget;
6232 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6233 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6234 checkGLcall("glDrawBuffers()");
6235 } else {
6236 glDrawBuffer(This->draw_buffers[0]);
6237 checkGLcall("glDrawBuffer()");
6239 } else {
6240 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6243 check_fbo_status(iface);
6246 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6247 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6249 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6250 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6251 GLenum gl_filter;
6253 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6254 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6255 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6256 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6258 switch (filter) {
6259 case WINED3DTEXF_LINEAR:
6260 gl_filter = GL_LINEAR;
6261 break;
6263 default:
6264 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6265 case WINED3DTEXF_NONE:
6266 case WINED3DTEXF_POINT:
6267 gl_filter = GL_NEAREST;
6268 break;
6271 /* Attach src surface to src fbo */
6272 src_swapchain = get_swapchain(src_surface);
6273 if (src_swapchain) {
6274 GLenum buffer;
6276 TRACE("Source surface %p is onscreen\n", src_surface);
6277 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6278 /* Make sure the drawable is up to date. In the offscreen case
6279 * attach_surface_fbo() implicitly takes care of this. */
6280 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6282 ENTER_GL();
6283 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6284 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6285 glReadBuffer(buffer);
6286 checkGLcall("glReadBuffer()");
6288 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6289 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6290 } else {
6291 TRACE("Source surface %p is offscreen\n", src_surface);
6292 ENTER_GL();
6293 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6294 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6295 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6296 checkGLcall("glReadBuffer()");
6298 LEAVE_GL();
6300 /* Attach dst surface to dst fbo */
6301 dst_swapchain = get_swapchain(dst_surface);
6302 if (dst_swapchain) {
6303 GLenum buffer;
6305 TRACE("Destination surface %p is onscreen\n", dst_surface);
6306 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6307 /* Make sure the drawable is up to date. In the offscreen case
6308 * attach_surface_fbo() implicitly takes care of this. */
6309 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6311 ENTER_GL();
6312 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6313 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6314 glDrawBuffer(buffer);
6315 checkGLcall("glDrawBuffer()");
6317 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6318 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6319 } else {
6320 TRACE("Destination surface %p is offscreen\n", dst_surface);
6322 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6323 if(!src_swapchain) {
6324 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6327 ENTER_GL();
6328 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6329 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6330 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6331 checkGLcall("glDrawBuffer()");
6333 glDisable(GL_SCISSOR_TEST);
6334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6336 if (flip) {
6337 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6338 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6339 checkGLcall("glBlitFramebuffer()");
6340 } else {
6341 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6342 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6343 checkGLcall("glBlitFramebuffer()");
6346 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6348 if (This->render_offscreen) {
6349 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6350 } else {
6351 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6352 checkGLcall("glBindFramebuffer()");
6355 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6356 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6357 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6358 glDrawBuffer(GL_BACK);
6359 checkGLcall("glDrawBuffer()");
6361 LEAVE_GL();
6364 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6366 WINED3DVIEWPORT viewport;
6368 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6370 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6371 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6372 This, RenderTargetIndex, GL_LIMITS(buffers));
6373 return WINED3DERR_INVALIDCALL;
6376 /* MSDN says that null disables the render target
6377 but a device must always be associated with a render target
6378 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6380 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6381 for more details
6383 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6384 FIXME("Trying to set render target 0 to NULL\n");
6385 return WINED3DERR_INVALIDCALL;
6387 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6388 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);
6389 return WINED3DERR_INVALIDCALL;
6392 /* If we are trying to set what we already have, don't bother */
6393 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6394 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6395 return WINED3D_OK;
6397 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6398 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6399 This->render_targets[RenderTargetIndex] = pRenderTarget;
6401 /* Render target 0 is special */
6402 if(RenderTargetIndex == 0) {
6403 /* Finally, reset the viewport as the MSDN states. */
6404 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6405 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6406 viewport.X = 0;
6407 viewport.Y = 0;
6408 viewport.MaxZ = 1.0f;
6409 viewport.MinZ = 0.0f;
6410 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6411 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6412 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6416 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6417 * ctx properly.
6418 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6419 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6421 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6423 return WINED3D_OK;
6426 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6428 HRESULT hr = WINED3D_OK;
6429 IWineD3DSurface *tmp;
6431 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6433 if (pNewZStencil == This->stencilBufferTarget) {
6434 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6435 } else {
6436 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6437 * depending on the renter target implementation being used.
6438 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6439 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6440 * stencil buffer and incur an extra memory overhead
6441 ******************************************************/
6443 tmp = This->stencilBufferTarget;
6444 This->stencilBufferTarget = pNewZStencil;
6445 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6446 /* should we be calling the parent or the wined3d surface? */
6447 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6448 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6449 hr = WINED3D_OK;
6451 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6452 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6459 return hr;
6462 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6463 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6465 /* TODO: the use of Impl is deprecated. */
6466 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6467 WINED3DLOCKED_RECT lockedRect;
6469 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6471 /* some basic validation checks */
6472 if(This->cursorTexture) {
6473 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6474 ENTER_GL();
6475 glDeleteTextures(1, &This->cursorTexture);
6476 LEAVE_GL();
6477 This->cursorTexture = 0;
6480 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6481 This->haveHardwareCursor = TRUE;
6482 else
6483 This->haveHardwareCursor = FALSE;
6485 if(pCursorBitmap) {
6486 WINED3DLOCKED_RECT rect;
6488 /* MSDN: Cursor must be A8R8G8B8 */
6489 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6490 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6491 return WINED3DERR_INVALIDCALL;
6494 /* MSDN: Cursor must be smaller than the display mode */
6495 if(pSur->currentDesc.Width > This->ddraw_width ||
6496 pSur->currentDesc.Height > This->ddraw_height) {
6497 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);
6498 return WINED3DERR_INVALIDCALL;
6501 if (!This->haveHardwareCursor) {
6502 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6504 /* Do not store the surface's pointer because the application may
6505 * release it after setting the cursor image. Windows doesn't
6506 * addref the set surface, so we can't do this either without
6507 * creating circular refcount dependencies. Copy out the gl texture
6508 * instead.
6510 This->cursorWidth = pSur->currentDesc.Width;
6511 This->cursorHeight = pSur->currentDesc.Height;
6512 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6514 const GlPixelFormatDesc *glDesc;
6515 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6516 char *mem, *bits = (char *)rect.pBits;
6517 GLint intfmt = glDesc->glInternal;
6518 GLint format = glDesc->glFormat;
6519 GLint type = glDesc->glType;
6520 INT height = This->cursorHeight;
6521 INT width = This->cursorWidth;
6522 INT bpp = tableEntry->bpp;
6523 INT i;
6525 /* Reformat the texture memory (pitch and width can be
6526 * different) */
6527 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6528 for(i = 0; i < height; i++)
6529 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6530 IWineD3DSurface_UnlockRect(pCursorBitmap);
6531 ENTER_GL();
6533 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6534 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6535 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6538 /* Make sure that a proper texture unit is selected */
6539 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6540 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6541 checkGLcall("glActiveTextureARB");
6543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6544 /* Create a new cursor texture */
6545 glGenTextures(1, &This->cursorTexture);
6546 checkGLcall("glGenTextures");
6547 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6548 checkGLcall("glBindTexture");
6549 /* Copy the bitmap memory into the cursor texture */
6550 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6551 HeapFree(GetProcessHeap(), 0, mem);
6552 checkGLcall("glTexImage2D");
6554 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6555 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6556 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6559 LEAVE_GL();
6561 else
6563 FIXME("A cursor texture was not returned.\n");
6564 This->cursorTexture = 0;
6567 else
6569 /* Draw a hardware cursor */
6570 ICONINFO cursorInfo;
6571 HCURSOR cursor;
6572 /* Create and clear maskBits because it is not needed for
6573 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6574 * chunks. */
6575 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6576 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6577 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6578 WINED3DLOCK_NO_DIRTY_UPDATE |
6579 WINED3DLOCK_READONLY
6581 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6582 pSur->currentDesc.Height);
6584 cursorInfo.fIcon = FALSE;
6585 cursorInfo.xHotspot = XHotSpot;
6586 cursorInfo.yHotspot = YHotSpot;
6587 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6588 pSur->currentDesc.Height, 1,
6589 1, &maskBits);
6590 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6591 pSur->currentDesc.Height, 1,
6592 32, lockedRect.pBits);
6593 IWineD3DSurface_UnlockRect(pCursorBitmap);
6594 /* Create our cursor and clean up. */
6595 cursor = CreateIconIndirect(&cursorInfo);
6596 SetCursor(cursor);
6597 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6598 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6599 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6600 This->hardwareCursor = cursor;
6601 HeapFree(GetProcessHeap(), 0, maskBits);
6605 This->xHotSpot = XHotSpot;
6606 This->yHotSpot = YHotSpot;
6607 return WINED3D_OK;
6610 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6612 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6614 This->xScreenSpace = XScreenSpace;
6615 This->yScreenSpace = YScreenSpace;
6617 return;
6621 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6623 BOOL oldVisible = This->bCursorVisible;
6624 POINT pt;
6626 TRACE("(%p) : visible(%d)\n", This, bShow);
6629 * When ShowCursor is first called it should make the cursor appear at the OS's last
6630 * known cursor position. Because of this, some applications just repetitively call
6631 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6633 GetCursorPos(&pt);
6634 This->xScreenSpace = pt.x;
6635 This->yScreenSpace = pt.y;
6637 if (This->haveHardwareCursor) {
6638 This->bCursorVisible = bShow;
6639 if (bShow)
6640 SetCursor(This->hardwareCursor);
6641 else
6642 SetCursor(NULL);
6644 else
6646 if (This->cursorTexture)
6647 This->bCursorVisible = bShow;
6650 return oldVisible;
6653 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6655 IWineD3DResourceImpl *resource;
6656 TRACE("(%p) : state (%u)\n", This, This->state);
6658 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6659 switch (This->state) {
6660 case WINED3D_OK:
6661 return WINED3D_OK;
6662 case WINED3DERR_DEVICELOST:
6664 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6665 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6666 return WINED3DERR_DEVICENOTRESET;
6668 return WINED3DERR_DEVICELOST;
6670 case WINED3DERR_DRIVERINTERNALERROR:
6671 return WINED3DERR_DRIVERINTERNALERROR;
6674 /* Unknown state */
6675 return WINED3DERR_DRIVERINTERNALERROR;
6679 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6681 /** FIXME: Resource tracking needs to be done,
6682 * The closes we can do to this is set the priorities of all managed textures low
6683 * and then reset them.
6684 ***********************************************************/
6685 FIXME("(%p) : stub\n", This);
6686 return WINED3D_OK;
6689 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6690 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6692 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6693 if(surface->Flags & SFLAG_DIBSECTION) {
6694 /* Release the DC */
6695 SelectObject(surface->hDC, surface->dib.holdbitmap);
6696 DeleteDC(surface->hDC);
6697 /* Release the DIB section */
6698 DeleteObject(surface->dib.DIBsection);
6699 surface->dib.bitmap_data = NULL;
6700 surface->resource.allocatedMemory = NULL;
6701 surface->Flags &= ~SFLAG_DIBSECTION;
6703 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6704 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6705 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6706 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6707 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6708 } else {
6709 surface->pow2Width = surface->pow2Height = 1;
6710 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6711 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6713 surface->glRect.left = 0;
6714 surface->glRect.top = 0;
6715 surface->glRect.right = surface->pow2Width;
6716 surface->glRect.bottom = surface->pow2Height;
6718 if(surface->glDescription.textureName) {
6719 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6720 ENTER_GL();
6721 glDeleteTextures(1, &surface->glDescription.textureName);
6722 LEAVE_GL();
6723 surface->glDescription.textureName = 0;
6724 surface->Flags &= ~SFLAG_CLIENT;
6726 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6727 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6728 surface->Flags |= SFLAG_NONPOW2;
6729 } else {
6730 surface->Flags &= ~SFLAG_NONPOW2;
6732 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6733 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6736 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6737 TRACE("Unloading resource %p\n", resource);
6738 IWineD3DResource_UnLoad(resource);
6739 IWineD3DResource_Release(resource);
6740 return S_OK;
6743 static void reset_fbo_state(IWineD3DDevice *iface) {
6744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6745 unsigned int i;
6747 ENTER_GL();
6748 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6749 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6751 if (This->fbo) {
6752 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6753 This->fbo = 0;
6755 if (This->src_fbo) {
6756 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6757 This->src_fbo = 0;
6759 if (This->dst_fbo) {
6760 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6761 This->dst_fbo = 0;
6763 checkGLcall("Tear down fbos\n");
6764 LEAVE_GL();
6766 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6767 This->fbo_color_attachments[i] = NULL;
6769 This->fbo_depth_attachment = NULL;
6772 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6773 UINT i, count;
6774 WINED3DDISPLAYMODE m;
6775 HRESULT hr;
6777 /* All Windowed modes are supported, as is leaving the current mode */
6778 if(pp->Windowed) return TRUE;
6779 if(!pp->BackBufferWidth) return TRUE;
6780 if(!pp->BackBufferHeight) return TRUE;
6782 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6783 for(i = 0; i < count; i++) {
6784 memset(&m, 0, sizeof(m));
6785 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6786 if(FAILED(hr)) {
6787 ERR("EnumAdapterModes failed\n");
6789 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6790 /* Mode found, it is supported */
6791 return TRUE;
6794 /* Mode not found -> not supported */
6795 return FALSE;
6798 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6800 IWineD3DSwapChainImpl *swapchain;
6801 HRESULT hr;
6802 BOOL DisplayModeChanged = FALSE;
6803 WINED3DDISPLAYMODE mode;
6804 IWineD3DBaseShaderImpl *shader;
6805 IWineD3DSurfaceImpl *target;
6806 UINT i;
6807 TRACE("(%p)\n", This);
6809 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6810 if(FAILED(hr)) {
6811 ERR("Failed to get the first implicit swapchain\n");
6812 return hr;
6815 if(!is_display_mode_supported(This, pPresentationParameters)) {
6816 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6817 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6818 pPresentationParameters->BackBufferHeight);
6819 return WINED3DERR_INVALIDCALL;
6822 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6823 * on an existing gl context, so there's no real need for recreation.
6825 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6827 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6829 TRACE("New params:\n");
6830 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6831 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6832 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6833 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6834 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6835 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6836 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6837 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6838 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6839 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6840 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6841 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6842 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6844 /* No special treatment of these parameters. Just store them */
6845 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6846 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6847 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6848 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6850 /* What to do about these? */
6851 if(pPresentationParameters->BackBufferCount != 0 &&
6852 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6853 ERR("Cannot change the back buffer count yet\n");
6855 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6856 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6857 ERR("Cannot change the back buffer format yet\n");
6859 if(pPresentationParameters->hDeviceWindow != NULL &&
6860 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6861 ERR("Cannot change the device window yet\n");
6863 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6864 ERR("What do do about a changed auto depth stencil parameter?\n");
6867 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6868 reset_fbo_state((IWineD3DDevice *) This);
6871 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6872 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6873 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6876 ENTER_GL();
6877 if(This->depth_blt_texture) {
6878 glDeleteTextures(1, &This->depth_blt_texture);
6879 This->depth_blt_texture = 0;
6881 This->shader_backend->shader_destroy_depth_blt(iface);
6883 for (i = 0; i < GL_LIMITS(textures); i++) {
6884 /* The stateblock initialization below will recreate them */
6885 glDeleteTextures(1, &This->dummyTextureName[i]);
6886 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6887 This->dummyTextureName[i] = 0;
6889 LEAVE_GL();
6891 while(This->numContexts) {
6892 DestroyContext(This, This->contexts[0]);
6894 This->activeContext = NULL;
6895 HeapFree(GetProcessHeap(), 0, swapchain->context);
6896 swapchain->context = NULL;
6897 swapchain->num_contexts = 0;
6899 if(pPresentationParameters->Windowed) {
6900 mode.Width = swapchain->orig_width;
6901 mode.Height = swapchain->orig_height;
6902 mode.RefreshRate = 0;
6903 mode.Format = swapchain->presentParms.BackBufferFormat;
6904 } else {
6905 mode.Width = pPresentationParameters->BackBufferWidth;
6906 mode.Height = pPresentationParameters->BackBufferHeight;
6907 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6908 mode.Format = swapchain->presentParms.BackBufferFormat;
6911 /* Should Width == 800 && Height == 0 set 800x600? */
6912 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6913 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6914 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6916 WINED3DVIEWPORT vp;
6917 int i;
6919 vp.X = 0;
6920 vp.Y = 0;
6921 vp.Width = pPresentationParameters->BackBufferWidth;
6922 vp.Height = pPresentationParameters->BackBufferHeight;
6923 vp.MinZ = 0;
6924 vp.MaxZ = 1;
6926 if(!pPresentationParameters->Windowed) {
6927 DisplayModeChanged = TRUE;
6929 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6930 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6932 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6933 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6934 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6936 if(This->auto_depth_stencil_buffer) {
6937 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6941 /* Now set the new viewport */
6942 IWineD3DDevice_SetViewport(iface, &vp);
6945 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6946 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6947 DisplayModeChanged) {
6949 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6950 if(!pPresentationParameters->Windowed) {
6951 IWineD3DDevice_SetFullscreen(iface, TRUE);
6954 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6956 /* Switching out of fullscreen mode? First set the original res, then change the window */
6957 if(pPresentationParameters->Windowed) {
6958 IWineD3DDevice_SetFullscreen(iface, FALSE);
6960 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6961 } else if(!pPresentationParameters->Windowed) {
6962 DWORD style = This->style, exStyle = This->exStyle;
6963 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6964 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6965 * Reset to clear up their mess. Guild Wars also loses the device during that.
6967 This->style = 0;
6968 This->exStyle = 0;
6969 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
6970 This->style = style;
6971 This->exStyle = exStyle;
6974 /* Recreate the primary swapchain's context */
6975 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6976 if(swapchain->backBuffer) {
6977 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6978 } else {
6979 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6981 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6982 &swapchain->presentParms);
6983 swapchain->num_contexts = 1;
6984 This->activeContext = swapchain->context[0];
6986 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6987 if(FAILED(hr)) {
6988 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6991 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6992 * first use
6995 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6996 return WINED3D_OK;
6999 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7001 /** FIXME: always true at the moment **/
7002 if(!bEnableDialogs) {
7003 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7005 return WINED3D_OK;
7009 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7011 TRACE("(%p) : pParameters %p\n", This, pParameters);
7013 *pParameters = This->createParms;
7014 return WINED3D_OK;
7017 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7018 IWineD3DSwapChain *swapchain;
7019 HRESULT hrc = WINED3D_OK;
7021 TRACE("Relaying to swapchain\n");
7023 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7024 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7025 IWineD3DSwapChain_Release(swapchain);
7027 return;
7030 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7031 IWineD3DSwapChain *swapchain;
7032 HRESULT hrc = WINED3D_OK;
7034 TRACE("Relaying to swapchain\n");
7036 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7037 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7038 IWineD3DSwapChain_Release(swapchain);
7040 return;
7044 /** ********************************************************
7045 * Notification functions
7046 ** ********************************************************/
7047 /** This function must be called in the release of a resource when ref == 0,
7048 * the contents of resource must still be correct,
7049 * any handles to other resource held by the caller must be closed
7050 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7051 *****************************************************/
7052 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7055 TRACE("(%p) : Adding Resource %p\n", This, resource);
7056 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7059 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7062 TRACE("(%p) : Removing resource %p\n", This, resource);
7064 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7068 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7070 int counter;
7072 TRACE("(%p) : resource %p\n", This, resource);
7073 switch(IWineD3DResource_GetType(resource)){
7074 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7075 case WINED3DRTYPE_SURFACE: {
7076 unsigned int i;
7078 /* Cleanup any FBO attachments if d3d is enabled */
7079 if(This->d3d_initialized) {
7080 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7081 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7083 TRACE("Last active render target destroyed\n");
7084 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7085 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7086 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7087 * and the lastActiveRenderTarget member shouldn't matter
7089 if(swapchain) {
7090 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7091 TRACE("Activating primary back buffer\n");
7092 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7093 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7094 /* Single buffering environment */
7095 TRACE("Activating primary front buffer\n");
7096 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7097 } else {
7098 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7099 /* Implicit render target destroyed, that means the device is being destroyed
7100 * whatever we set here, it shouldn't matter
7102 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7104 } else {
7105 /* May happen during ddraw uninitialization */
7106 TRACE("Render target set, but swapchain does not exist!\n");
7107 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7111 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7112 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7113 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7114 set_render_target_fbo(iface, i, NULL);
7115 This->fbo_color_attachments[i] = NULL;
7118 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7119 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7120 set_depth_stencil_fbo(iface, NULL);
7121 This->fbo_depth_attachment = NULL;
7125 break;
7127 case WINED3DRTYPE_TEXTURE:
7128 case WINED3DRTYPE_CUBETEXTURE:
7129 case WINED3DRTYPE_VOLUMETEXTURE:
7130 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7131 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7132 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7133 This->stateBlock->textures[counter] = NULL;
7135 if (This->updateStateBlock != This->stateBlock ){
7136 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7137 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7138 This->updateStateBlock->textures[counter] = NULL;
7142 break;
7143 case WINED3DRTYPE_VOLUME:
7144 /* TODO: nothing really? */
7145 break;
7146 case WINED3DRTYPE_VERTEXBUFFER:
7147 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7149 int streamNumber;
7150 TRACE("Cleaning up stream pointers\n");
7152 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7153 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7154 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7156 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7157 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7158 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7159 This->updateStateBlock->streamSource[streamNumber] = 0;
7160 /* Set changed flag? */
7163 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) */
7164 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7165 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7166 This->stateBlock->streamSource[streamNumber] = 0;
7169 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7170 else { /* This shouldn't happen */
7171 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7173 #endif
7177 break;
7178 case WINED3DRTYPE_INDEXBUFFER:
7179 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7180 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7181 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7182 This->updateStateBlock->pIndexData = NULL;
7185 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7186 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7187 This->stateBlock->pIndexData = NULL;
7191 break;
7192 default:
7193 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7194 break;
7198 /* Remove the resource from the resourceStore */
7199 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7201 TRACE("Resource released\n");
7205 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7207 IWineD3DResourceImpl *resource, *cursor;
7208 HRESULT ret;
7209 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7211 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7212 TRACE("enumerating resource %p\n", resource);
7213 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7214 ret = pCallback((IWineD3DResource *) resource, pData);
7215 if(ret == S_FALSE) {
7216 TRACE("Canceling enumeration\n");
7217 break;
7220 return WINED3D_OK;
7223 /**********************************************************
7224 * IWineD3DDevice VTbl follows
7225 **********************************************************/
7227 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7229 /*** IUnknown methods ***/
7230 IWineD3DDeviceImpl_QueryInterface,
7231 IWineD3DDeviceImpl_AddRef,
7232 IWineD3DDeviceImpl_Release,
7233 /*** IWineD3DDevice methods ***/
7234 IWineD3DDeviceImpl_GetParent,
7235 /*** Creation methods**/
7236 IWineD3DDeviceImpl_CreateVertexBuffer,
7237 IWineD3DDeviceImpl_CreateIndexBuffer,
7238 IWineD3DDeviceImpl_CreateStateBlock,
7239 IWineD3DDeviceImpl_CreateSurface,
7240 IWineD3DDeviceImpl_CreateTexture,
7241 IWineD3DDeviceImpl_CreateVolumeTexture,
7242 IWineD3DDeviceImpl_CreateVolume,
7243 IWineD3DDeviceImpl_CreateCubeTexture,
7244 IWineD3DDeviceImpl_CreateQuery,
7245 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7246 IWineD3DDeviceImpl_CreateVertexDeclaration,
7247 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7248 IWineD3DDeviceImpl_CreateVertexShader,
7249 IWineD3DDeviceImpl_CreatePixelShader,
7250 IWineD3DDeviceImpl_CreatePalette,
7251 /*** Odd functions **/
7252 IWineD3DDeviceImpl_Init3D,
7253 IWineD3DDeviceImpl_Uninit3D,
7254 IWineD3DDeviceImpl_SetFullscreen,
7255 IWineD3DDeviceImpl_SetMultithreaded,
7256 IWineD3DDeviceImpl_EvictManagedResources,
7257 IWineD3DDeviceImpl_GetAvailableTextureMem,
7258 IWineD3DDeviceImpl_GetBackBuffer,
7259 IWineD3DDeviceImpl_GetCreationParameters,
7260 IWineD3DDeviceImpl_GetDeviceCaps,
7261 IWineD3DDeviceImpl_GetDirect3D,
7262 IWineD3DDeviceImpl_GetDisplayMode,
7263 IWineD3DDeviceImpl_SetDisplayMode,
7264 IWineD3DDeviceImpl_GetHWND,
7265 IWineD3DDeviceImpl_SetHWND,
7266 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7267 IWineD3DDeviceImpl_GetRasterStatus,
7268 IWineD3DDeviceImpl_GetSwapChain,
7269 IWineD3DDeviceImpl_Reset,
7270 IWineD3DDeviceImpl_SetDialogBoxMode,
7271 IWineD3DDeviceImpl_SetCursorProperties,
7272 IWineD3DDeviceImpl_SetCursorPosition,
7273 IWineD3DDeviceImpl_ShowCursor,
7274 IWineD3DDeviceImpl_TestCooperativeLevel,
7275 /*** Getters and setters **/
7276 IWineD3DDeviceImpl_SetClipPlane,
7277 IWineD3DDeviceImpl_GetClipPlane,
7278 IWineD3DDeviceImpl_SetClipStatus,
7279 IWineD3DDeviceImpl_GetClipStatus,
7280 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7281 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7282 IWineD3DDeviceImpl_SetDepthStencilSurface,
7283 IWineD3DDeviceImpl_GetDepthStencilSurface,
7284 IWineD3DDeviceImpl_SetFVF,
7285 IWineD3DDeviceImpl_GetFVF,
7286 IWineD3DDeviceImpl_SetGammaRamp,
7287 IWineD3DDeviceImpl_GetGammaRamp,
7288 IWineD3DDeviceImpl_SetIndices,
7289 IWineD3DDeviceImpl_GetIndices,
7290 IWineD3DDeviceImpl_SetBaseVertexIndex,
7291 IWineD3DDeviceImpl_GetBaseVertexIndex,
7292 IWineD3DDeviceImpl_SetLight,
7293 IWineD3DDeviceImpl_GetLight,
7294 IWineD3DDeviceImpl_SetLightEnable,
7295 IWineD3DDeviceImpl_GetLightEnable,
7296 IWineD3DDeviceImpl_SetMaterial,
7297 IWineD3DDeviceImpl_GetMaterial,
7298 IWineD3DDeviceImpl_SetNPatchMode,
7299 IWineD3DDeviceImpl_GetNPatchMode,
7300 IWineD3DDeviceImpl_SetPaletteEntries,
7301 IWineD3DDeviceImpl_GetPaletteEntries,
7302 IWineD3DDeviceImpl_SetPixelShader,
7303 IWineD3DDeviceImpl_GetPixelShader,
7304 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7305 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7306 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7307 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7308 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7309 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7310 IWineD3DDeviceImpl_SetRenderState,
7311 IWineD3DDeviceImpl_GetRenderState,
7312 IWineD3DDeviceImpl_SetRenderTarget,
7313 IWineD3DDeviceImpl_GetRenderTarget,
7314 IWineD3DDeviceImpl_SetFrontBackBuffers,
7315 IWineD3DDeviceImpl_SetSamplerState,
7316 IWineD3DDeviceImpl_GetSamplerState,
7317 IWineD3DDeviceImpl_SetScissorRect,
7318 IWineD3DDeviceImpl_GetScissorRect,
7319 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7320 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7321 IWineD3DDeviceImpl_SetStreamSource,
7322 IWineD3DDeviceImpl_GetStreamSource,
7323 IWineD3DDeviceImpl_SetStreamSourceFreq,
7324 IWineD3DDeviceImpl_GetStreamSourceFreq,
7325 IWineD3DDeviceImpl_SetTexture,
7326 IWineD3DDeviceImpl_GetTexture,
7327 IWineD3DDeviceImpl_SetTextureStageState,
7328 IWineD3DDeviceImpl_GetTextureStageState,
7329 IWineD3DDeviceImpl_SetTransform,
7330 IWineD3DDeviceImpl_GetTransform,
7331 IWineD3DDeviceImpl_SetVertexDeclaration,
7332 IWineD3DDeviceImpl_GetVertexDeclaration,
7333 IWineD3DDeviceImpl_SetVertexShader,
7334 IWineD3DDeviceImpl_GetVertexShader,
7335 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7336 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7337 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7338 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7339 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7340 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7341 IWineD3DDeviceImpl_SetViewport,
7342 IWineD3DDeviceImpl_GetViewport,
7343 IWineD3DDeviceImpl_MultiplyTransform,
7344 IWineD3DDeviceImpl_ValidateDevice,
7345 IWineD3DDeviceImpl_ProcessVertices,
7346 /*** State block ***/
7347 IWineD3DDeviceImpl_BeginStateBlock,
7348 IWineD3DDeviceImpl_EndStateBlock,
7349 /*** Scene management ***/
7350 IWineD3DDeviceImpl_BeginScene,
7351 IWineD3DDeviceImpl_EndScene,
7352 IWineD3DDeviceImpl_Present,
7353 IWineD3DDeviceImpl_Clear,
7354 /*** Drawing ***/
7355 IWineD3DDeviceImpl_DrawPrimitive,
7356 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7357 IWineD3DDeviceImpl_DrawPrimitiveUP,
7358 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7359 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7360 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7361 IWineD3DDeviceImpl_DrawRectPatch,
7362 IWineD3DDeviceImpl_DrawTriPatch,
7363 IWineD3DDeviceImpl_DeletePatch,
7364 IWineD3DDeviceImpl_ColorFill,
7365 IWineD3DDeviceImpl_UpdateTexture,
7366 IWineD3DDeviceImpl_UpdateSurface,
7367 IWineD3DDeviceImpl_GetFrontBufferData,
7368 /*** object tracking ***/
7369 IWineD3DDeviceImpl_ResourceReleased,
7370 IWineD3DDeviceImpl_EnumResources
7374 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7375 WINED3DRS_ALPHABLENDENABLE ,
7376 WINED3DRS_ALPHAFUNC ,
7377 WINED3DRS_ALPHAREF ,
7378 WINED3DRS_ALPHATESTENABLE ,
7379 WINED3DRS_BLENDOP ,
7380 WINED3DRS_COLORWRITEENABLE ,
7381 WINED3DRS_DESTBLEND ,
7382 WINED3DRS_DITHERENABLE ,
7383 WINED3DRS_FILLMODE ,
7384 WINED3DRS_FOGDENSITY ,
7385 WINED3DRS_FOGEND ,
7386 WINED3DRS_FOGSTART ,
7387 WINED3DRS_LASTPIXEL ,
7388 WINED3DRS_SHADEMODE ,
7389 WINED3DRS_SRCBLEND ,
7390 WINED3DRS_STENCILENABLE ,
7391 WINED3DRS_STENCILFAIL ,
7392 WINED3DRS_STENCILFUNC ,
7393 WINED3DRS_STENCILMASK ,
7394 WINED3DRS_STENCILPASS ,
7395 WINED3DRS_STENCILREF ,
7396 WINED3DRS_STENCILWRITEMASK ,
7397 WINED3DRS_STENCILZFAIL ,
7398 WINED3DRS_TEXTUREFACTOR ,
7399 WINED3DRS_WRAP0 ,
7400 WINED3DRS_WRAP1 ,
7401 WINED3DRS_WRAP2 ,
7402 WINED3DRS_WRAP3 ,
7403 WINED3DRS_WRAP4 ,
7404 WINED3DRS_WRAP5 ,
7405 WINED3DRS_WRAP6 ,
7406 WINED3DRS_WRAP7 ,
7407 WINED3DRS_ZENABLE ,
7408 WINED3DRS_ZFUNC ,
7409 WINED3DRS_ZWRITEENABLE
7412 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7413 WINED3DTSS_ADDRESSW ,
7414 WINED3DTSS_ALPHAARG0 ,
7415 WINED3DTSS_ALPHAARG1 ,
7416 WINED3DTSS_ALPHAARG2 ,
7417 WINED3DTSS_ALPHAOP ,
7418 WINED3DTSS_BUMPENVLOFFSET ,
7419 WINED3DTSS_BUMPENVLSCALE ,
7420 WINED3DTSS_BUMPENVMAT00 ,
7421 WINED3DTSS_BUMPENVMAT01 ,
7422 WINED3DTSS_BUMPENVMAT10 ,
7423 WINED3DTSS_BUMPENVMAT11 ,
7424 WINED3DTSS_COLORARG0 ,
7425 WINED3DTSS_COLORARG1 ,
7426 WINED3DTSS_COLORARG2 ,
7427 WINED3DTSS_COLOROP ,
7428 WINED3DTSS_RESULTARG ,
7429 WINED3DTSS_TEXCOORDINDEX ,
7430 WINED3DTSS_TEXTURETRANSFORMFLAGS
7433 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7434 WINED3DSAMP_ADDRESSU ,
7435 WINED3DSAMP_ADDRESSV ,
7436 WINED3DSAMP_ADDRESSW ,
7437 WINED3DSAMP_BORDERCOLOR ,
7438 WINED3DSAMP_MAGFILTER ,
7439 WINED3DSAMP_MINFILTER ,
7440 WINED3DSAMP_MIPFILTER ,
7441 WINED3DSAMP_MIPMAPLODBIAS ,
7442 WINED3DSAMP_MAXMIPLEVEL ,
7443 WINED3DSAMP_MAXANISOTROPY ,
7444 WINED3DSAMP_SRGBTEXTURE ,
7445 WINED3DSAMP_ELEMENTINDEX
7448 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7449 WINED3DRS_AMBIENT ,
7450 WINED3DRS_AMBIENTMATERIALSOURCE ,
7451 WINED3DRS_CLIPPING ,
7452 WINED3DRS_CLIPPLANEENABLE ,
7453 WINED3DRS_COLORVERTEX ,
7454 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7455 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7456 WINED3DRS_FOGDENSITY ,
7457 WINED3DRS_FOGEND ,
7458 WINED3DRS_FOGSTART ,
7459 WINED3DRS_FOGTABLEMODE ,
7460 WINED3DRS_FOGVERTEXMODE ,
7461 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7462 WINED3DRS_LIGHTING ,
7463 WINED3DRS_LOCALVIEWER ,
7464 WINED3DRS_MULTISAMPLEANTIALIAS ,
7465 WINED3DRS_MULTISAMPLEMASK ,
7466 WINED3DRS_NORMALIZENORMALS ,
7467 WINED3DRS_PATCHEDGESTYLE ,
7468 WINED3DRS_POINTSCALE_A ,
7469 WINED3DRS_POINTSCALE_B ,
7470 WINED3DRS_POINTSCALE_C ,
7471 WINED3DRS_POINTSCALEENABLE ,
7472 WINED3DRS_POINTSIZE ,
7473 WINED3DRS_POINTSIZE_MAX ,
7474 WINED3DRS_POINTSIZE_MIN ,
7475 WINED3DRS_POINTSPRITEENABLE ,
7476 WINED3DRS_RANGEFOGENABLE ,
7477 WINED3DRS_SPECULARMATERIALSOURCE ,
7478 WINED3DRS_TWEENFACTOR ,
7479 WINED3DRS_VERTEXBLEND ,
7480 WINED3DRS_CULLMODE ,
7481 WINED3DRS_FOGCOLOR
7484 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7485 WINED3DTSS_TEXCOORDINDEX ,
7486 WINED3DTSS_TEXTURETRANSFORMFLAGS
7489 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7490 WINED3DSAMP_DMAPOFFSET
7493 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7494 DWORD rep = StateTable[state].representative;
7495 DWORD idx;
7496 BYTE shift;
7497 UINT i;
7498 WineD3DContext *context;
7500 if(!rep) return;
7501 for(i = 0; i < This->numContexts; i++) {
7502 context = This->contexts[i];
7503 if(isStateDirty(context, rep)) continue;
7505 context->dirtyArray[context->numDirtyEntries++] = rep;
7506 idx = rep >> 5;
7507 shift = rep & 0x1f;
7508 context->isStateDirty[idx] |= (1 << shift);
7512 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7513 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7514 /* The drawable size of a pbuffer render target is the current pbuffer size
7516 *width = dev->pbufferWidth;
7517 *height = dev->pbufferHeight;
7520 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7521 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7523 *width = This->pow2Width;
7524 *height = This->pow2Height;
7527 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7528 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7529 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7530 * current context's drawable, which is the size of the back buffer of the swapchain
7531 * the active context belongs to. The back buffer of the swapchain is stored as the
7532 * surface the context belongs to.
7534 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7535 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;