2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
141 if (IsEqualGUID(riid, &IID_IUnknown)
142 || IsEqualGUID(riid, &IID_IWineD3DBase)
143 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
144 IUnknown_AddRef(iface);
149 return E_NOINTERFACE;
152 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 ULONG refCount = InterlockedIncrement(&This->ref);
156 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
160 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
162 ULONG refCount = InterlockedDecrement(&This->ref);
164 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This->resources)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
173 dumpResources(&This->resources);
176 if(This->contexts) ERR("Context array not freed!\n");
177 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
178 This->haveHardwareCursor = FALSE;
180 IWineD3D_Release(This->wineD3D);
181 This->wineD3D = NULL;
182 HeapFree(GetProcessHeap(), 0, This);
183 TRACE("Freed device %p\n", This);
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
194 *pParent = This->parent;
195 IUnknown_AddRef(This->parent);
199 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
200 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 IWineD3DVertexBufferImpl *object;
204 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
205 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer = NULL;
211 return WINED3DERR_INVALIDCALL;
212 } else if(Pool == WINED3DPOOL_SCRATCH) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer = NULL;
218 return WINED3DERR_INVALIDCALL;
221 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
223 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);
224 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion <= 7 && conv) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
253 object->Flags |= VBFLAG_CREATEVBO;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
259 GLenum error, glUsage;
260 TRACE("Creating VBO for Index Buffer %p\n", object);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
273 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
274 error = glGetError();
275 if(error != GL_NO_ERROR || object->vbo == 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
281 error = glGetError();
282 if(error != GL_NO_ERROR) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage = GL_STATIC_DRAW_ARB;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
298 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
308 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
309 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
310 HANDLE *sharedHandle, IUnknown *parent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DIndexBufferImpl *object;
313 TRACE("(%p) Creating index buffer\n", This);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
318 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
319 CreateIndexBufferVBO(This, object);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
323 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
324 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
332 IWineD3DStateBlockImpl *object;
336 D3DCREATEOBJECTINSTANCE(object, StateBlock)
337 object->blockType = Type;
339 for(i = 0; i < LIGHTMAP_SIZE; i++) {
340 list_init(&object->lightMap[i]);
343 temp_result = allocate_shader_constants(object);
344 if (FAILED(temp_result))
346 HeapFree(GetProcessHeap(), 0, object);
350 /* Special case - Used during initialization to produce a placeholder stateblock
351 so other functions called can update a state block */
352 if (Type == WINED3DSBT_INIT) {
353 /* Don't bother increasing the reference count otherwise a device will never
354 be freed due to circular dependencies */
358 /* Otherwise, might as well set the whole state block to the appropriate values */
359 if (This->stateBlock != NULL)
360 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
362 memset(object->streamFreq, 1, sizeof(object->streamFreq));
364 /* Reset the ref and type after kludging it */
365 object->wineD3DDevice = This;
367 object->blockType = Type;
369 TRACE("Updating changed flags appropriate for type %d\n", Type);
371 if (Type == WINED3DSBT_ALL) {
373 TRACE("ALL => Pretend everything has changed\n");
374 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
376 /* Lights are not part of the changed / set structure */
377 for(j = 0; j < LIGHTMAP_SIZE; j++) {
379 LIST_FOR_EACH(e, &object->lightMap[j]) {
380 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
381 light->changed = TRUE;
382 light->enabledChanged = TRUE;
385 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
386 object->contained_render_states[j - 1] = j;
388 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
389 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
390 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
391 object->contained_transform_states[j - 1] = j;
393 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
394 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
395 object->contained_vs_consts_f[j] = j;
397 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
398 for(j = 0; j < MAX_CONST_I; j++) {
399 object->contained_vs_consts_i[j] = j;
401 object->num_contained_vs_consts_i = MAX_CONST_I;
402 for(j = 0; j < MAX_CONST_B; j++) {
403 object->contained_vs_consts_b[j] = j;
405 object->num_contained_vs_consts_b = MAX_CONST_B;
406 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
407 object->contained_ps_consts_f[j] = j;
409 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
410 for(j = 0; j < MAX_CONST_I; j++) {
411 object->contained_ps_consts_i[j] = j;
413 object->num_contained_ps_consts_i = MAX_CONST_I;
414 for(j = 0; j < MAX_CONST_B; j++) {
415 object->contained_ps_consts_b[j] = j;
417 object->num_contained_ps_consts_b = MAX_CONST_B;
418 for(i = 0; i < MAX_TEXTURES; i++) {
419 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
420 object->contained_tss_states[object->num_contained_tss_states].stage = i;
421 object->contained_tss_states[object->num_contained_tss_states].state = j;
422 object->num_contained_tss_states++;
425 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
426 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
427 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
428 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
429 object->num_contained_sampler_states++;
433 for(i = 0; i < MAX_STREAMS; i++) {
434 if(object->streamSource[i]) {
435 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
438 if(object->pIndexData) {
439 IWineD3DIndexBuffer_AddRef(object->pIndexData);
441 if(object->vertexShader) {
442 IWineD3DVertexShader_AddRef(object->vertexShader);
444 if(object->pixelShader) {
445 IWineD3DPixelShader_AddRef(object->pixelShader);
448 } else if (Type == WINED3DSBT_PIXELSTATE) {
450 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
451 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
453 object->changed.pixelShader = TRUE;
455 /* Pixel Shader Constants */
456 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
457 object->contained_ps_consts_f[i] = i;
458 object->changed.pixelShaderConstantsF[i] = TRUE;
460 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
461 for (i = 0; i < MAX_CONST_B; ++i) {
462 object->contained_ps_consts_b[i] = i;
463 object->changed.pixelShaderConstantsB |= (1 << i);
465 object->num_contained_ps_consts_b = MAX_CONST_B;
466 for (i = 0; i < MAX_CONST_I; ++i) {
467 object->contained_ps_consts_i[i] = i;
468 object->changed.pixelShaderConstantsI |= (1 << i);
470 object->num_contained_ps_consts_i = MAX_CONST_I;
472 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
473 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
474 object->contained_render_states[i] = SavedPixelStates_R[i];
476 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
477 for (j = 0; j < MAX_TEXTURES; j++) {
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
479 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
480 object->contained_tss_states[object->num_contained_tss_states].stage = j;
481 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
482 object->num_contained_tss_states++;
485 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
486 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
487 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
488 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
489 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
490 object->num_contained_sampler_states++;
493 if(object->pixelShader) {
494 IWineD3DPixelShader_AddRef(object->pixelShader);
497 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
498 * on them. This makes releasing the buffer easier
500 for(i = 0; i < MAX_STREAMS; i++) {
501 object->streamSource[i] = NULL;
503 object->pIndexData = NULL;
504 object->vertexShader = NULL;
506 } else if (Type == WINED3DSBT_VERTEXSTATE) {
508 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
509 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
511 object->changed.vertexShader = TRUE;
513 /* Vertex Shader Constants */
514 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
515 object->changed.vertexShaderConstantsF[i] = TRUE;
516 object->contained_vs_consts_f[i] = i;
518 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
519 for (i = 0; i < MAX_CONST_B; ++i) {
520 object->contained_vs_consts_b[i] = i;
521 object->changed.vertexShaderConstantsB |= (1 << i);
523 object->num_contained_vs_consts_b = MAX_CONST_B;
524 for (i = 0; i < MAX_CONST_I; ++i) {
525 object->contained_vs_consts_i[i] = i;
526 object->changed.vertexShaderConstantsI |= (1 << i);
528 object->num_contained_vs_consts_i = MAX_CONST_I;
529 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
530 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
531 object->contained_render_states[i] = SavedVertexStates_R[i];
533 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
534 for (j = 0; j < MAX_TEXTURES; j++) {
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
536 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
537 object->contained_tss_states[object->num_contained_tss_states].stage = j;
538 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
539 object->num_contained_tss_states++;
542 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
545 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
546 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
547 object->num_contained_sampler_states++;
551 for(j = 0; j < LIGHTMAP_SIZE; j++) {
553 LIST_FOR_EACH(e, &object->lightMap[j]) {
554 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
555 light->changed = TRUE;
556 light->enabledChanged = TRUE;
560 for(i = 0; i < MAX_STREAMS; i++) {
561 if(object->streamSource[i]) {
562 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
565 if(object->vertexShader) {
566 IWineD3DVertexShader_AddRef(object->vertexShader);
568 object->pIndexData = NULL;
569 object->pixelShader = NULL;
571 FIXME("Unrecognized state block type %d\n", Type);
574 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
578 /* ************************************
580 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
583 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
585 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.
587 ******************************** */
589 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) {
590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
591 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
592 unsigned int Size = 1;
593 const struct GlPixelFormatDesc *glDesc;
594 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
596 TRACE("(%p) Create surface\n",This);
598 /** FIXME: Check ranges on the inputs are valid
601 * [in] Quality level. The valid range is between zero and one less than the level
602 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
603 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
604 * values of paired render targets, depth stencil surfaces, and the MultiSample type
606 *******************************/
611 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
613 * If this flag is set, the contents of the depth stencil buffer will be
614 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
615 * with a different depth surface.
617 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
618 ***************************/
620 if(MultisampleQuality > 0) {
621 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
622 MultisampleQuality=0;
625 /** FIXME: Check that the format is supported
627 *******************************/
629 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
630 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
632 *********************************/
633 mul_4w = (Width + 3) & ~3;
634 mul_4h = (Height + 3) & ~3;
635 if (WINED3DFMT_UNKNOWN == Format) {
637 } else if (Format == WINED3DFMT_DXT1) {
638 /* DXT1 is half byte per pixel */
639 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
641 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
642 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
643 Format == WINED3DFMT_ATI2N) {
644 Size = (mul_4w * tableEntry->bpp * mul_4h);
646 /* The pitch is a multiple of 4 bytes */
647 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
651 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
663 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
664 list_init(&object->overlays);
667 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
668 object->Flags |= Discard ? SFLAG_DISCARD : 0;
669 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
670 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
673 if (WINED3DFMT_UNKNOWN != Format) {
674 object->bytesPerPixel = tableEntry->bpp;
676 object->bytesPerPixel = 0;
679 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
681 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
683 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
684 * this function is too deep to need to care about things like this.
685 * Levels need to be checked too, and possibly Type since they all affect what can be done.
686 * ****************************************/
688 case WINED3DPOOL_SCRATCH:
690 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
691 "which are mutually exclusive, setting lockable to TRUE\n");
694 case WINED3DPOOL_SYSTEMMEM:
695 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
696 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
697 case WINED3DPOOL_MANAGED:
698 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
699 "Usage of DYNAMIC which are mutually exclusive, not doing "
700 "anything just telling you.\n");
702 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
703 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
704 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
705 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
708 FIXME("(%p) Unknown pool %d\n", This, Pool);
712 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
713 FIXME("Trying to create a render target that isn't in the default pool\n");
716 /* mark the texture as dirty so that it gets loaded first time around*/
717 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
718 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
719 This, Width, Height, Format, debug_d3dformat(Format),
720 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
722 /* Look at the implementation and set the correct Vtable */
725 /* Check if a 3D adapter is available when creating gl surfaces */
727 ERR("OpenGL surfaces are not available without opengl\n");
728 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
729 HeapFree(GetProcessHeap(), 0, object);
730 return WINED3DERR_NOTAVAILABLE;
735 object->lpVtbl = &IWineGDISurface_Vtbl;
739 /* To be sure to catch this */
740 ERR("Unknown requested surface implementation %d!\n", Impl);
741 IWineD3DSurface_Release((IWineD3DSurface *) object);
742 return WINED3DERR_INVALIDCALL;
745 list_init(&object->renderbuffers);
747 /* Call the private setup routine */
748 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
752 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
753 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
754 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
755 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
758 IWineD3DTextureImpl *object;
763 unsigned int pow2Width;
764 unsigned int pow2Height;
765 const struct GlPixelFormatDesc *glDesc;
766 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
768 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
769 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
770 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
772 /* TODO: It should only be possible to create textures for formats
773 that are reported as supported */
774 if (WINED3DFMT_UNKNOWN >= Format) {
775 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
776 return WINED3DERR_INVALIDCALL;
779 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
780 D3DINITIALIZEBASETEXTURE(object->baseTexture);
781 object->width = Width;
782 object->height = Height;
784 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
785 object->baseTexture.minMipLookup = minMipLookup;
786 object->baseTexture.magLookup = magLookup;
788 object->baseTexture.minMipLookup = minMipLookup_noFilter;
789 object->baseTexture.magLookup = magLookup_noFilter;
792 /** Non-power2 support **/
793 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
797 /* Find the nearest pow2 match */
798 pow2Width = pow2Height = 1;
799 while (pow2Width < Width) pow2Width <<= 1;
800 while (pow2Height < Height) pow2Height <<= 1;
802 if(pow2Width != Width || pow2Height != Height) {
804 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
805 HeapFree(GetProcessHeap(), 0, object);
807 return WINED3DERR_INVALIDCALL;
814 /** FIXME: add support for real non-power-two if it's provided by the video card **/
815 /* Precalculated scaling for 'faked' non power of two texture coords.
816 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
817 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
818 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
820 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
821 object->baseTexture.pow2Matrix[0] = 1.0;
822 object->baseTexture.pow2Matrix[5] = 1.0;
823 object->baseTexture.pow2Matrix[10] = 1.0;
824 object->baseTexture.pow2Matrix[15] = 1.0;
825 object->target = GL_TEXTURE_2D;
826 object->cond_np2 = TRUE;
827 object->baseTexture.minMipLookup = minMipLookup_noFilter;
828 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
829 (Width != pow2Width || Height != pow2Height) &&
830 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
832 object->baseTexture.pow2Matrix[0] = (float)Width;
833 object->baseTexture.pow2Matrix[5] = (float)Height;
834 object->baseTexture.pow2Matrix[10] = 1.0;
835 object->baseTexture.pow2Matrix[15] = 1.0;
836 object->target = GL_TEXTURE_RECTANGLE_ARB;
837 object->cond_np2 = TRUE;
838 object->baseTexture.minMipLookup = minMipLookup_noFilter;
840 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
841 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
842 object->baseTexture.pow2Matrix[10] = 1.0;
843 object->baseTexture.pow2Matrix[15] = 1.0;
844 object->target = GL_TEXTURE_2D;
845 object->cond_np2 = FALSE;
847 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
849 /* Calculate levels for mip mapping */
850 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
851 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
852 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
853 return WINED3DERR_INVALIDCALL;
856 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
857 return WINED3DERR_INVALIDCALL;
859 object->baseTexture.levels = 1;
860 } else if (Levels == 0) {
861 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
862 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
865 /* Generate all the surfaces */
868 for (i = 0; i < object->baseTexture.levels; i++)
870 /* use the callback to create the texture surface */
871 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
872 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
873 FIXME("Failed to create surface %p\n", object);
875 object->surfaces[i] = NULL;
876 IWineD3DTexture_Release((IWineD3DTexture *)object);
882 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
883 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
884 surface_set_texture_target(object->surfaces[i], object->target);
885 /* calculate the next mipmap level */
886 tmpW = max(1, tmpW >> 1);
887 tmpH = max(1, tmpH >> 1);
889 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
891 TRACE("(%p) : Created texture %p\n", This, object);
895 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
896 UINT Width, UINT Height, UINT Depth,
897 UINT Levels, DWORD Usage,
898 WINED3DFORMAT Format, WINED3DPOOL Pool,
899 IWineD3DVolumeTexture **ppVolumeTexture,
900 HANDLE *pSharedHandle, IUnknown *parent,
901 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
904 IWineD3DVolumeTextureImpl *object;
909 const struct GlPixelFormatDesc *glDesc;
911 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
913 /* TODO: It should only be possible to create textures for formats
914 that are reported as supported */
915 if (WINED3DFMT_UNKNOWN >= Format) {
916 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
917 return WINED3DERR_INVALIDCALL;
919 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
920 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
921 return WINED3DERR_INVALIDCALL;
924 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
925 D3DINITIALIZEBASETEXTURE(object->baseTexture);
927 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
928 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
930 /* Is NP2 support for volumes needed? */
931 object->baseTexture.pow2Matrix[ 0] = 1.0;
932 object->baseTexture.pow2Matrix[ 5] = 1.0;
933 object->baseTexture.pow2Matrix[10] = 1.0;
934 object->baseTexture.pow2Matrix[15] = 1.0;
936 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
937 object->baseTexture.minMipLookup = minMipLookup;
938 object->baseTexture.magLookup = magLookup;
940 object->baseTexture.minMipLookup = minMipLookup_noFilter;
941 object->baseTexture.magLookup = magLookup_noFilter;
944 /* Calculate levels for mip mapping */
945 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
946 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
947 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
948 return WINED3DERR_INVALIDCALL;
951 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
952 return WINED3DERR_INVALIDCALL;
954 object->baseTexture.levels = 1;
955 } else if (Levels == 0) {
956 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
957 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
960 /* Generate all the surfaces */
965 for (i = 0; i < object->baseTexture.levels; i++)
968 /* Create the volume */
969 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
970 &object->volumes[i], pSharedHandle);
973 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
974 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
975 *ppVolumeTexture = NULL;
979 /* Set its container to this object */
980 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
982 /* calculate the next mipmap level */
983 tmpW = max(1, tmpW >> 1);
984 tmpH = max(1, tmpH >> 1);
985 tmpD = max(1, tmpD >> 1);
987 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
989 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
990 TRACE("(%p) : Created volume texture %p\n", This, object);
994 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
995 UINT Width, UINT Height, UINT Depth,
997 WINED3DFORMAT Format, WINED3DPOOL Pool,
998 IWineD3DVolume** ppVolume,
999 HANDLE* pSharedHandle, IUnknown *parent) {
1001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1002 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1003 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1005 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1006 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1007 return WINED3DERR_INVALIDCALL;
1010 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1012 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1013 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1015 object->currentDesc.Width = Width;
1016 object->currentDesc.Height = Height;
1017 object->currentDesc.Depth = Depth;
1018 object->bytesPerPixel = formatDesc->bpp;
1020 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1021 object->lockable = TRUE;
1022 object->locked = FALSE;
1023 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1024 object->dirty = TRUE;
1026 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1029 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1030 UINT Levels, DWORD Usage,
1031 WINED3DFORMAT Format, WINED3DPOOL Pool,
1032 IWineD3DCubeTexture **ppCubeTexture,
1033 HANDLE *pSharedHandle, IUnknown *parent,
1034 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1037 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1041 unsigned int pow2EdgeLength;
1042 const struct GlPixelFormatDesc *glDesc;
1043 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1045 /* TODO: It should only be possible to create textures for formats
1046 that are reported as supported */
1047 if (WINED3DFMT_UNKNOWN >= Format) {
1048 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1049 return WINED3DERR_INVALIDCALL;
1052 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1053 WARN("(%p) : Tried to create not supported cube texture\n", This);
1054 return WINED3DERR_INVALIDCALL;
1057 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1058 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1060 TRACE("(%p) Create Cube Texture\n", This);
1062 /* Find the nearest pow2 match */
1064 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1066 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1067 /* Precalculated scaling for 'faked' non power of two texture coords */
1068 object->baseTexture.pow2Matrix[ 0] = 1.0;
1069 object->baseTexture.pow2Matrix[ 5] = 1.0;
1070 object->baseTexture.pow2Matrix[10] = 1.0;
1071 object->baseTexture.pow2Matrix[15] = 1.0;
1073 /* Precalculated scaling for 'faked' non power of two texture coords */
1074 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1075 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1076 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1077 object->baseTexture.pow2Matrix[15] = 1.0;
1080 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1081 object->baseTexture.minMipLookup = minMipLookup;
1082 object->baseTexture.magLookup = magLookup;
1084 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1085 object->baseTexture.magLookup = magLookup_noFilter;
1088 /* Calculate levels for mip mapping */
1089 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1090 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1091 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1092 HeapFree(GetProcessHeap(), 0, object);
1093 *ppCubeTexture = NULL;
1095 return WINED3DERR_INVALIDCALL;
1098 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1099 HeapFree(GetProcessHeap(), 0, object);
1100 *ppCubeTexture = NULL;
1102 return WINED3DERR_INVALIDCALL;
1104 object->baseTexture.levels = 1;
1105 } else if (Levels == 0) {
1106 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1107 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1110 /* Generate all the surfaces */
1112 for (i = 0; i < object->baseTexture.levels; i++) {
1114 /* Create the 6 faces */
1115 for (j = 0; j < 6; j++) {
1116 static const GLenum cube_targets[6] = {
1117 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1118 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1119 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1120 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1121 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1122 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1125 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1126 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1128 if(hr!= WINED3D_OK) {
1132 for (l = 0; l < j; l++) {
1133 IWineD3DSurface_Release(object->surfaces[l][i]);
1135 for (k = 0; k < i; k++) {
1136 for (l = 0; l < 6; l++) {
1137 IWineD3DSurface_Release(object->surfaces[l][k]);
1141 FIXME("(%p) Failed to create surface\n",object);
1142 HeapFree(GetProcessHeap(),0,object);
1143 *ppCubeTexture = NULL;
1146 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1147 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1148 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1150 tmpW = max(1, tmpW >> 1);
1152 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1154 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1155 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1159 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1161 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1162 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1163 const IWineD3DQueryVtbl *vtable;
1165 /* Just a check to see if we support this type of query */
1167 case WINED3DQUERYTYPE_OCCLUSION:
1168 TRACE("(%p) occlusion query\n", This);
1169 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1172 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1174 vtable = &IWineD3DOcclusionQuery_Vtbl;
1177 case WINED3DQUERYTYPE_EVENT:
1178 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1179 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1180 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1182 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1184 vtable = &IWineD3DEventQuery_Vtbl;
1188 case WINED3DQUERYTYPE_VCACHE:
1189 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1190 case WINED3DQUERYTYPE_VERTEXSTATS:
1191 case WINED3DQUERYTYPE_TIMESTAMP:
1192 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1193 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1194 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1195 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1196 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1197 case WINED3DQUERYTYPE_PIXELTIMINGS:
1198 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1199 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1201 /* Use the base Query vtable until we have a special one for each query */
1202 vtable = &IWineD3DQuery_Vtbl;
1203 FIXME("(%p) Unhandled query type %d\n", This, Type);
1205 if(NULL == ppQuery || hr != WINED3D_OK) {
1209 D3DCREATEOBJECTINSTANCE(object, Query)
1210 object->lpVtbl = vtable;
1211 object->type = Type;
1212 object->state = QUERY_CREATED;
1213 /* allocated the 'extended' data based on the type of query requested */
1215 case WINED3DQUERYTYPE_OCCLUSION:
1216 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1217 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1219 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1220 TRACE("(%p) Allocating data for an occlusion query\n", This);
1222 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1224 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1228 case WINED3DQUERYTYPE_EVENT:
1229 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1230 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1232 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1234 if(GL_SUPPORT(APPLE_FENCE)) {
1235 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesAPPLE");
1237 } else if(GL_SUPPORT(NV_FENCE)) {
1238 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1239 checkGLcall("glGenFencesNV");
1244 case WINED3DQUERYTYPE_VCACHE:
1245 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1246 case WINED3DQUERYTYPE_VERTEXSTATS:
1247 case WINED3DQUERYTYPE_TIMESTAMP:
1248 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1249 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1250 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1251 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1252 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1253 case WINED3DQUERYTYPE_PIXELTIMINGS:
1254 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1255 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1257 object->extendedData = 0;
1258 FIXME("(%p) Unhandled query type %d\n",This , Type);
1260 TRACE("(%p) : Created Query %p\n", This, object);
1264 /*****************************************************************************
1265 * IWineD3DDeviceImpl_SetupFullscreenWindow
1267 * Helper function that modifies a HWND's Style and ExStyle for proper
1271 * iface: Pointer to the IWineD3DDevice interface
1272 * window: Window to setup
1274 *****************************************************************************/
1275 static LONG fullscreen_style(LONG orig_style) {
1276 LONG style = orig_style;
1277 style &= ~WS_CAPTION;
1278 style &= ~WS_THICKFRAME;
1280 /* Make sure the window is managed, otherwise we won't get keyboard input */
1281 style |= WS_POPUP | WS_SYSMENU;
1286 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1287 LONG exStyle = orig_exStyle;
1289 /* Filter out window decorations */
1290 exStyle &= ~WS_EX_WINDOWEDGE;
1291 exStyle &= ~WS_EX_CLIENTEDGE;
1296 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 LONG style, exStyle;
1300 /* Don't do anything if an original style is stored.
1301 * That shouldn't happen
1303 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1304 if (This->style || This->exStyle) {
1305 ERR("(%p): Want to change the window parameters of HWND %p, but "
1306 "another style is stored for restoration afterwards\n", This, window);
1309 /* Get the parameters and save them */
1310 style = GetWindowLongW(window, GWL_STYLE);
1311 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1312 This->style = style;
1313 This->exStyle = exStyle;
1315 style = fullscreen_style(style);
1316 exStyle = fullscreen_exStyle(exStyle);
1318 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1319 This->style, This->exStyle, style, exStyle);
1321 SetWindowLongW(window, GWL_STYLE, style);
1322 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1324 /* Inform the window about the update. */
1325 SetWindowPos(window, HWND_TOP, 0, 0,
1326 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1329 /*****************************************************************************
1330 * IWineD3DDeviceImpl_RestoreWindow
1332 * Helper function that restores a windows' properties when taking it out
1333 * of fullscreen mode
1336 * iface: Pointer to the IWineD3DDevice interface
1337 * window: Window to setup
1339 *****************************************************************************/
1340 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1342 LONG style, exStyle;
1344 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1345 * switch, do nothing
1347 if (!This->style && !This->exStyle) return;
1349 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1350 This, window, This->style, This->exStyle);
1352 style = GetWindowLongW(window, GWL_STYLE);
1353 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1355 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1356 * Some applications change it before calling Reset() when switching between windowed and
1357 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1359 if(style == fullscreen_style(This->style) &&
1360 exStyle == fullscreen_style(This->exStyle)) {
1361 SetWindowLongW(window, GWL_STYLE, This->style);
1362 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1365 /* Delete the old values */
1369 /* Inform the window about the update */
1370 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1371 0, 0, 0, 0, /* Pos, Size, ignored */
1372 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1375 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1376 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1377 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1378 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1379 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1384 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1386 IUnknown *bufferParent;
1387 BOOL displaymode_set = FALSE;
1388 WINED3DDISPLAYMODE Mode;
1389 const StaticPixelFormatDesc *formatDesc;
1391 TRACE("(%p) : Created Additional Swap Chain\n", This);
1393 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1394 * does a device hold a reference to a swap chain giving them a lifetime of the device
1395 * or does the swap chain notify the device of its destruction.
1396 *******************************/
1398 /* Check the params */
1399 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1400 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1401 return WINED3DERR_INVALIDCALL;
1402 } else if (pPresentationParameters->BackBufferCount > 1) {
1403 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");
1406 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1407 switch(surface_type) {
1409 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1411 case SURFACE_OPENGL:
1412 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1414 case SURFACE_UNKNOWN:
1415 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1416 return WINED3DERR_INVALIDCALL;
1419 /*********************
1420 * Lookup the window Handle and the relating X window handle
1421 ********************/
1423 /* Setup hwnd we are using, plus which display this equates to */
1424 object->win_handle = pPresentationParameters->hDeviceWindow;
1425 if (!object->win_handle) {
1426 object->win_handle = This->createParms.hFocusWindow;
1428 if(!pPresentationParameters->Windowed && object->win_handle) {
1429 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1430 pPresentationParameters->BackBufferWidth,
1431 pPresentationParameters->BackBufferHeight);
1434 hDc = GetDC(object->win_handle);
1435 TRACE("Using hDc %p\n", hDc);
1438 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1439 return WINED3DERR_NOTAVAILABLE;
1442 /* Get info on the current display setup */
1443 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1444 object->orig_width = Mode.Width;
1445 object->orig_height = Mode.Height;
1446 object->orig_fmt = Mode.Format;
1447 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1449 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1450 * then the corresponding dimension of the client area of the hDeviceWindow
1451 * (or the focus window, if hDeviceWindow is NULL) is taken.
1452 **********************/
1454 if (pPresentationParameters->Windowed &&
1455 ((pPresentationParameters->BackBufferWidth == 0) ||
1456 (pPresentationParameters->BackBufferHeight == 0) ||
1457 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1460 GetClientRect(object->win_handle, &Rect);
1462 if (pPresentationParameters->BackBufferWidth == 0) {
1463 pPresentationParameters->BackBufferWidth = Rect.right;
1464 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1466 if (pPresentationParameters->BackBufferHeight == 0) {
1467 pPresentationParameters->BackBufferHeight = Rect.bottom;
1468 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1470 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1471 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1472 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1476 /* Put the correct figures in the presentation parameters */
1477 TRACE("Copying across presentation parameters\n");
1478 object->presentParms = *pPresentationParameters;
1480 TRACE("calling rendertarget CB\n");
1481 hr = D3DCB_CreateRenderTarget(This->parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.BackBufferFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 TRUE /* Lockable */,
1489 &object->frontBuffer,
1490 NULL /* pShared (always null)*/);
1491 if (SUCCEEDED(hr)) {
1492 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1493 if(surface_type == SURFACE_OPENGL) {
1494 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1497 ERR("Failed to create the front buffer\n");
1501 /*********************
1502 * Windowed / Fullscreen
1503 *******************/
1506 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1507 * so we should really check to see if there is a fullscreen swapchain already
1508 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1509 **************************************/
1511 if (!pPresentationParameters->Windowed) {
1512 WINED3DDISPLAYMODE mode;
1515 /* Change the display settings */
1516 mode.Width = pPresentationParameters->BackBufferWidth;
1517 mode.Height = pPresentationParameters->BackBufferHeight;
1518 mode.Format = pPresentationParameters->BackBufferFormat;
1519 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1521 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1522 displaymode_set = TRUE;
1526 * Create an opengl context for the display visual
1527 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1528 * use different properties after that point in time. FIXME: How to handle when requested format
1529 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1530 * it chooses is identical to the one already being used!
1531 **********************************/
1532 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1534 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1535 if(!object->context) {
1536 ERR("Failed to create the context array\n");
1540 object->num_contexts = 1;
1542 if(surface_type == SURFACE_OPENGL) {
1543 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1544 if (!object->context[0]) {
1545 ERR("Failed to create a new context\n");
1546 hr = WINED3DERR_NOTAVAILABLE;
1549 TRACE("Context created (HWND=%p, glContext=%p)\n",
1550 object->win_handle, object->context[0]->glCtx);
1554 /*********************
1555 * Create the back, front and stencil buffers
1556 *******************/
1557 if(object->presentParms.BackBufferCount > 0) {
1560 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1561 if(!object->backBuffer) {
1562 ERR("Out of memory\n");
1567 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1568 TRACE("calling rendertarget CB\n");
1569 hr = D3DCB_CreateRenderTarget(This->parent,
1571 object->presentParms.BackBufferWidth,
1572 object->presentParms.BackBufferHeight,
1573 object->presentParms.BackBufferFormat,
1574 object->presentParms.MultiSampleType,
1575 object->presentParms.MultiSampleQuality,
1576 TRUE /* Lockable */,
1577 &object->backBuffer[i],
1578 NULL /* pShared (always null)*/);
1580 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1582 ERR("Cannot create new back buffer\n");
1585 if(surface_type == SURFACE_OPENGL) {
1587 glDrawBuffer(GL_BACK);
1588 checkGLcall("glDrawBuffer(GL_BACK)");
1593 object->backBuffer = NULL;
1595 /* Single buffering - draw to front buffer */
1596 if(surface_type == SURFACE_OPENGL) {
1598 glDrawBuffer(GL_FRONT);
1599 checkGLcall("glDrawBuffer(GL_FRONT)");
1604 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1605 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1606 TRACE("Creating depth stencil buffer\n");
1607 if (This->auto_depth_stencil_buffer == NULL ) {
1608 hr = D3DCB_CreateDepthStencil(This->parent,
1610 object->presentParms.BackBufferWidth,
1611 object->presentParms.BackBufferHeight,
1612 object->presentParms.AutoDepthStencilFormat,
1613 object->presentParms.MultiSampleType,
1614 object->presentParms.MultiSampleQuality,
1615 FALSE /* FIXME: Discard */,
1616 &This->auto_depth_stencil_buffer,
1617 NULL /* pShared (always null)*/ );
1618 if (SUCCEEDED(hr)) {
1619 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1621 ERR("Failed to create the auto depth stencil\n");
1627 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1629 TRACE("Created swapchain %p\n", object);
1630 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1634 if (displaymode_set) {
1638 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1641 /* Change the display settings */
1642 memset(&devmode, 0, sizeof(devmode));
1643 devmode.dmSize = sizeof(devmode);
1644 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1645 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1646 devmode.dmPelsWidth = object->orig_width;
1647 devmode.dmPelsHeight = object->orig_height;
1648 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1651 if (object->backBuffer) {
1653 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1654 if(object->backBuffer[i]) {
1655 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1656 IUnknown_Release(bufferParent); /* once for the get parent */
1657 if (IUnknown_Release(bufferParent) > 0) {
1658 FIXME("(%p) Something's still holding the back buffer\n",This);
1662 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1663 object->backBuffer = NULL;
1665 if(object->context && object->context[0])
1666 DestroyContext(This, object->context[0]);
1667 if(object->frontBuffer) {
1668 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1669 IUnknown_Release(bufferParent); /* once for the get parent */
1670 if (IUnknown_Release(bufferParent) > 0) {
1671 FIXME("(%p) Something's still holding the front buffer\n",This);
1674 HeapFree(GetProcessHeap(), 0, object);
1678 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1679 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 TRACE("(%p)\n", This);
1683 return This->NumberOfSwapChains;
1686 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1688 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1690 if(iSwapChain < This->NumberOfSwapChains) {
1691 *pSwapChain = This->swapchains[iSwapChain];
1692 IWineD3DSwapChain_AddRef(*pSwapChain);
1693 TRACE("(%p) returning %p\n", This, *pSwapChain);
1696 TRACE("Swapchain out of range\n");
1698 return WINED3DERR_INVALIDCALL;
1703 * Vertex Declaration
1705 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1706 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1708 IWineD3DVertexDeclarationImpl *object = NULL;
1709 HRESULT hr = WINED3D_OK;
1711 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1712 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1714 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1716 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1718 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1719 *ppVertexDeclaration = NULL;
1725 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1726 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1728 unsigned int idx, idx2;
1729 unsigned int offset;
1730 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1731 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1732 BOOL has_blend_idx = has_blend &&
1733 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1734 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1735 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1736 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1737 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1738 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1739 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1741 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1742 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1744 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1745 WINED3DVERTEXELEMENT *elements = NULL;
1748 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1749 if (has_blend_idx) num_blends--;
1751 /* Compute declaration size */
1752 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1753 has_psize + has_diffuse + has_specular + num_textures + 1;
1755 /* convert the declaration */
1756 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1760 elements[size-1] = end_element;
1763 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1765 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1767 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1768 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1769 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1772 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1773 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1775 elements[idx].UsageIndex = 0;
1778 if (has_blend && (num_blends > 0)) {
1779 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1780 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1782 switch(num_blends) {
1783 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1784 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1785 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1786 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1788 ERR("Unexpected amount of blend values: %u\n", num_blends);
1791 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1792 elements[idx].UsageIndex = 0;
1795 if (has_blend_idx) {
1796 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1797 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1798 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1799 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1800 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1802 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1803 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1804 elements[idx].UsageIndex = 0;
1808 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1809 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1810 elements[idx].UsageIndex = 0;
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1815 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1816 elements[idx].UsageIndex = 0;
1820 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1821 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1822 elements[idx].UsageIndex = 0;
1826 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1827 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1828 elements[idx].UsageIndex = 1;
1831 for (idx2 = 0; idx2 < num_textures; idx2++) {
1832 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1833 switch (numcoords) {
1834 case WINED3DFVF_TEXTUREFORMAT1:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1837 case WINED3DFVF_TEXTUREFORMAT2:
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1840 case WINED3DFVF_TEXTUREFORMAT3:
1841 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1843 case WINED3DFVF_TEXTUREFORMAT4:
1844 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1847 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1848 elements[idx].UsageIndex = idx2;
1852 /* Now compute offsets, and initialize the rest of the fields */
1853 for (idx = 0, offset = 0; idx < size-1; idx++) {
1854 elements[idx].Stream = 0;
1855 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1856 elements[idx].Offset = offset;
1857 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1860 *ppVertexElements = elements;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1865 WINED3DVERTEXELEMENT* elements = NULL;
1866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1870 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1871 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1873 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1874 HeapFree(GetProcessHeap(), 0, elements);
1875 if (hr != S_OK) return hr;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1883 HRESULT hr = WINED3D_OK;
1885 if (!pFunction) return WINED3DERR_INVALIDCALL;
1887 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1888 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1890 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1892 if (vertex_declaration) {
1893 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1896 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1898 if (WINED3D_OK != hr) {
1899 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1900 IWineD3DVertexShader_Release(*ppVertexShader);
1901 return WINED3DERR_INVALIDCALL;
1903 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1908 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1910 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1911 HRESULT hr = WINED3D_OK;
1913 if (!pFunction) return WINED3DERR_INVALIDCALL;
1915 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1916 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1917 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1918 if (WINED3D_OK == hr) {
1919 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1920 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1922 WARN("(%p) : Failed to create pixel shader\n", This);
1928 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1929 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1932 IWineD3DPaletteImpl *object;
1934 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1936 /* Create the new object */
1937 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1939 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1940 return E_OUTOFMEMORY;
1943 object->lpVtbl = &IWineD3DPalette_Vtbl;
1945 object->Flags = Flags;
1946 object->parent = Parent;
1947 object->wineD3DDevice = This;
1948 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1950 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1953 HeapFree( GetProcessHeap(), 0, object);
1954 return E_OUTOFMEMORY;
1957 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1959 IWineD3DPalette_Release((IWineD3DPalette *) object);
1963 *Palette = (IWineD3DPalette *) object;
1968 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1972 HDC dcb = NULL, dcs = NULL;
1973 WINEDDCOLORKEY colorkey;
1975 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1978 GetObjectA(hbm, sizeof(BITMAP), &bm);
1979 dcb = CreateCompatibleDC(NULL);
1981 SelectObject(dcb, hbm);
1985 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1986 * couldn't be loaded
1988 memset(&bm, 0, sizeof(bm));
1993 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1994 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1995 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1997 ERR("Wine logo requested, but failed to create surface\n");
2002 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2003 if(FAILED(hr)) goto out;
2004 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2005 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2007 colorkey.dwColorSpaceLowValue = 0;
2008 colorkey.dwColorSpaceHighValue = 0;
2009 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2011 /* Fill the surface with a white color to show that wined3d is there */
2012 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2025 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2027 /* Under DirectX you can have texture stage operations even if no texture is
2028 bound, whereas opengl will only do texture operations when a valid texture is
2029 bound. We emulate this by creating dummy textures and binding them to each
2030 texture stage, but disable all stages by default. Hence if a stage is enabled
2031 then the default texture will kick in until replaced by a SetTexture call */
2034 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2035 /* The dummy texture does not have client storage backing */
2036 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2037 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2039 for (i = 0; i < GL_LIMITS(textures); i++) {
2040 GLubyte white = 255;
2042 /* Make appropriate texture active */
2043 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2044 checkGLcall("glActiveTextureARB");
2046 /* Generate an opengl texture name */
2047 glGenTextures(1, &This->dummyTextureName[i]);
2048 checkGLcall("glGenTextures");
2049 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2051 /* Generate a dummy 2d texture (not using 1d because they cause many
2052 * DRI drivers fall back to sw) */
2053 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2054 checkGLcall("glBindTexture");
2056 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2057 checkGLcall("glTexImage2D");
2059 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2060 /* Reenable because if supported it is enabled by default */
2061 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2062 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2068 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2070 IWineD3DSwapChainImpl *swapchain = NULL;
2075 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2076 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2077 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2079 /* TODO: Test if OpenGL is compiled in and loaded */
2081 TRACE("(%p) : Creating stateblock\n", This);
2082 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2083 hr = IWineD3DDevice_CreateStateBlock(iface,
2085 (IWineD3DStateBlock **)&This->stateBlock,
2087 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2088 WARN("Failed to create stateblock\n");
2091 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2092 This->updateStateBlock = This->stateBlock;
2093 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2095 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2096 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2098 This->NumberOfPalettes = 1;
2099 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2100 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2101 ERR("Out of memory!\n");
2104 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2105 if(!This->palettes[0]) {
2106 ERR("Out of memory!\n");
2109 for (i = 0; i < 256; ++i) {
2110 This->palettes[0][i].peRed = 0xFF;
2111 This->palettes[0][i].peGreen = 0xFF;
2112 This->palettes[0][i].peBlue = 0xFF;
2113 This->palettes[0][i].peFlags = 0xFF;
2115 This->currentPalette = 0;
2117 /* Initialize the texture unit mapping to a 1:1 mapping */
2118 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2119 if (state < GL_LIMITS(fragment_samplers)) {
2120 This->texUnitMap[state] = state;
2121 This->rev_tex_unit_map[state] = state;
2123 This->texUnitMap[state] = -1;
2124 This->rev_tex_unit_map[state] = -1;
2128 /* Setup the implicit swapchain */
2129 TRACE("Creating implicit swapchain\n");
2130 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2131 if (FAILED(hr) || !swapchain) {
2132 WARN("Failed to create implicit swapchain\n");
2136 This->NumberOfSwapChains = 1;
2137 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2138 if(!This->swapchains) {
2139 ERR("Out of memory!\n");
2142 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2144 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2145 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2146 This->render_targets[0] = swapchain->backBuffer[0];
2147 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2150 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2151 This->render_targets[0] = swapchain->frontBuffer;
2152 This->lastActiveRenderTarget = swapchain->frontBuffer;
2154 IWineD3DSurface_AddRef(This->render_targets[0]);
2155 This->activeContext = swapchain->context[0];
2156 This->lastThread = GetCurrentThreadId();
2158 /* Depth Stencil support */
2159 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2160 if (NULL != This->stencilBufferTarget) {
2161 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2164 hr = This->shader_backend->shader_alloc_private(iface);
2166 TRACE("Shader private data couldn't be allocated\n");
2169 hr = This->frag_pipe->alloc_private(iface);
2171 TRACE("Fragment pipeline private data couldn't be allocated\n");
2174 hr = This->blitter->alloc_private(iface);
2176 TRACE("Blitter private data couldn't be allocated\n");
2180 /* Set up some starting GL setup */
2182 /* Setup all the devices defaults */
2183 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2184 create_dummy_textures(This);
2188 /* Initialize the current view state */
2189 This->view_ident = 1;
2190 This->contexts[0]->last_was_rhw = 0;
2191 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2192 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2194 switch(wined3d_settings.offscreen_rendering_mode) {
2197 This->offscreenBuffer = GL_BACK;
2200 case ORM_BACKBUFFER:
2202 if(This->activeContext->aux_buffers > 0) {
2203 TRACE("Using auxilliary buffer for offscreen rendering\n");
2204 This->offscreenBuffer = GL_AUX0;
2206 TRACE("Using back buffer for offscreen rendering\n");
2207 This->offscreenBuffer = GL_BACK;
2212 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2215 /* Clear the screen */
2216 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2217 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2220 This->d3d_initialized = TRUE;
2222 if(wined3d_settings.logo) {
2223 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2225 This->highest_dirty_ps_const = 0;
2226 This->highest_dirty_vs_const = 0;
2230 HeapFree(GetProcessHeap(), 0, This->render_targets);
2231 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2232 HeapFree(GetProcessHeap(), 0, This->swapchains);
2233 This->NumberOfSwapChains = 0;
2234 if(This->palettes) {
2235 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2236 HeapFree(GetProcessHeap(), 0, This->palettes);
2238 This->NumberOfPalettes = 0;
2240 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2242 if(This->stateBlock) {
2243 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2244 This->stateBlock = NULL;
2246 if (This->blit_priv) {
2247 This->blitter->free_private(iface);
2249 if (This->fragment_priv) {
2250 This->frag_pipe->free_private(iface);
2252 if (This->shader_priv) {
2253 This->shader_backend->shader_free_private(iface);
2258 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2260 IWineD3DSwapChainImpl *swapchain = NULL;
2263 /* Setup the implicit swapchain */
2264 TRACE("Creating implicit swapchain\n");
2265 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2266 if (FAILED(hr) || !swapchain) {
2267 WARN("Failed to create implicit swapchain\n");
2271 This->NumberOfSwapChains = 1;
2272 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2273 if(!This->swapchains) {
2274 ERR("Out of memory!\n");
2277 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2281 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2285 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2289 TRACE("(%p)\n", This);
2291 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2293 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2294 * it was created. Thus make sure a context is active for the glDelete* calls
2296 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2298 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2300 TRACE("Deleting high order patches\n");
2301 for(i = 0; i < PATCHMAP_SIZE; i++) {
2302 struct list *e1, *e2;
2303 struct WineD3DRectPatch *patch;
2304 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2305 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2306 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2310 /* Delete the palette conversion shader if it is around */
2311 if(This->paletteConversionShader) {
2313 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2315 This->paletteConversionShader = 0;
2318 /* Delete the pbuffer context if there is any */
2319 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2321 /* Delete the mouse cursor texture */
2322 if(This->cursorTexture) {
2324 glDeleteTextures(1, &This->cursorTexture);
2326 This->cursorTexture = 0;
2329 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2330 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2332 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2333 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2336 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2337 * private data, it might contain opengl pointers
2339 if(This->depth_blt_texture) {
2340 glDeleteTextures(1, &This->depth_blt_texture);
2341 This->depth_blt_texture = 0;
2343 if (This->depth_blt_rb) {
2344 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2345 This->depth_blt_rb = 0;
2346 This->depth_blt_rb_w = 0;
2347 This->depth_blt_rb_h = 0;
2350 /* Release the update stateblock */
2351 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2352 if(This->updateStateBlock != This->stateBlock)
2353 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2355 This->updateStateBlock = NULL;
2357 { /* because were not doing proper internal refcounts releasing the primary state block
2358 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2359 to set this->stateBlock = NULL; first */
2360 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2361 This->stateBlock = NULL;
2363 /* Release the stateblock */
2364 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2365 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2369 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2370 This->blitter->free_private(iface);
2371 This->frag_pipe->free_private(iface);
2372 This->shader_backend->shader_free_private(iface);
2374 /* Release the buffers (with sanity checks)*/
2375 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2376 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2377 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2378 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2380 This->stencilBufferTarget = NULL;
2382 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2383 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2384 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2386 TRACE("Setting rendertarget to NULL\n");
2387 This->render_targets[0] = NULL;
2389 if (This->auto_depth_stencil_buffer) {
2390 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2391 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2393 This->auto_depth_stencil_buffer = NULL;
2396 for(i=0; i < This->NumberOfSwapChains; i++) {
2397 TRACE("Releasing the implicit swapchain %d\n", i);
2398 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2399 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2403 HeapFree(GetProcessHeap(), 0, This->swapchains);
2404 This->swapchains = NULL;
2405 This->NumberOfSwapChains = 0;
2407 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2408 HeapFree(GetProcessHeap(), 0, This->palettes);
2409 This->palettes = NULL;
2410 This->NumberOfPalettes = 0;
2412 HeapFree(GetProcessHeap(), 0, This->render_targets);
2413 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2414 This->render_targets = NULL;
2415 This->draw_buffers = NULL;
2417 This->d3d_initialized = FALSE;
2421 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2425 for(i=0; i < This->NumberOfSwapChains; i++) {
2426 TRACE("Releasing the implicit swapchain %d\n", i);
2427 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2428 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2432 HeapFree(GetProcessHeap(), 0, This->swapchains);
2433 This->swapchains = NULL;
2434 This->NumberOfSwapChains = 0;
2438 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2439 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2440 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2442 * There is no way to deactivate thread safety once it is enabled.
2444 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2447 /*For now just store the flag(needed in case of ddraw) */
2448 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2453 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2454 const WINED3DDISPLAYMODE* pMode) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2461 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2463 /* Resize the screen even without a window:
2464 * The app could have unset it with SetCooperativeLevel, but not called
2465 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2466 * but we don't have any hwnd
2469 memset(&devmode, 0, sizeof(devmode));
2470 devmode.dmSize = sizeof(devmode);
2471 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2472 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2473 devmode.dmPelsWidth = pMode->Width;
2474 devmode.dmPelsHeight = pMode->Height;
2476 devmode.dmDisplayFrequency = pMode->RefreshRate;
2477 if (pMode->RefreshRate != 0) {
2478 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2481 /* Only change the mode if necessary */
2482 if( (This->ddraw_width == pMode->Width) &&
2483 (This->ddraw_height == pMode->Height) &&
2484 (This->ddraw_format == pMode->Format) &&
2485 (pMode->RefreshRate == 0) ) {
2489 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2490 if (ret != DISP_CHANGE_SUCCESSFUL) {
2491 if(devmode.dmDisplayFrequency != 0) {
2492 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2493 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2494 devmode.dmDisplayFrequency = 0;
2495 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2497 if(ret != DISP_CHANGE_SUCCESSFUL) {
2498 return WINED3DERR_NOTAVAILABLE;
2502 /* Store the new values */
2503 This->ddraw_width = pMode->Width;
2504 This->ddraw_height = pMode->Height;
2505 This->ddraw_format = pMode->Format;
2507 /* And finally clip mouse to our screen */
2508 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2509 ClipCursor(&clip_rc);
2514 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 *ppD3D= This->wineD3D;
2517 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2518 IWineD3D_AddRef(*ppD3D);
2522 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2525 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2526 (This->adapter->TextureRam/(1024*1024)),
2527 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2528 /* return simulated texture memory left */
2529 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2533 * Get / Set Stream Source
2535 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 IWineD3DVertexBuffer *oldSrc;
2539 if (StreamNumber >= MAX_STREAMS) {
2540 WARN("Stream out of range %d\n", StreamNumber);
2541 return WINED3DERR_INVALIDCALL;
2542 } else if(OffsetInBytes & 0x3) {
2543 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2544 return WINED3DERR_INVALIDCALL;
2547 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2548 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2550 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2552 if(oldSrc == pStreamData &&
2553 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2554 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2555 TRACE("Application is setting the old values over, nothing to do\n");
2559 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2561 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2562 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2565 /* Handle recording of state blocks */
2566 if (This->isRecordingState) {
2567 TRACE("Recording... not performing anything\n");
2568 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2569 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2573 /* Need to do a getParent and pass the references up */
2574 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2575 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2576 so for now, just count internally */
2577 if (pStreamData != NULL) {
2578 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2579 InterlockedIncrement(&vbImpl->bindCount);
2580 IWineD3DVertexBuffer_AddRef(pStreamData);
2582 if (oldSrc != NULL) {
2583 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2584 IWineD3DVertexBuffer_Release(oldSrc);
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2592 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2595 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2596 This->stateBlock->streamSource[StreamNumber],
2597 This->stateBlock->streamOffset[StreamNumber],
2598 This->stateBlock->streamStride[StreamNumber]);
2600 if (StreamNumber >= MAX_STREAMS) {
2601 WARN("Stream out of range %d\n", StreamNumber);
2602 return WINED3DERR_INVALIDCALL;
2604 *pStream = This->stateBlock->streamSource[StreamNumber];
2605 *pStride = This->stateBlock->streamStride[StreamNumber];
2607 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2610 if (*pStream != NULL) {
2611 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2616 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2618 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2619 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2621 /* Verify input at least in d3d9 this is invalid*/
2622 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2623 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2624 return WINED3DERR_INVALIDCALL;
2626 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2627 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2628 return WINED3DERR_INVALIDCALL;
2631 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2632 return WINED3DERR_INVALIDCALL;
2635 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2636 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2638 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2639 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2641 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2642 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2653 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2655 TRACE("(%p) : returning %d\n", This, *Divider);
2661 * Get / Set & Multiply Transform
2663 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 /* Most of this routine, comments included copied from ddraw tree initially: */
2667 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2669 /* Handle recording of state blocks */
2670 if (This->isRecordingState) {
2671 TRACE("Recording... not performing anything\n");
2672 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2673 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2678 * If the new matrix is the same as the current one,
2679 * we cut off any further processing. this seems to be a reasonable
2680 * optimization because as was noticed, some apps (warcraft3 for example)
2681 * tend towards setting the same matrix repeatedly for some reason.
2683 * From here on we assume that the new matrix is different, wherever it matters.
2685 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2686 TRACE("The app is setting the same matrix over again\n");
2689 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2693 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2694 where ViewMat = Camera space, WorldMat = world space.
2696 In OpenGL, camera and world space is combined into GL_MODELVIEW
2697 matrix. The Projection matrix stay projection matrix.
2700 /* Capture the times we can just ignore the change for now */
2701 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2702 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2703 /* Handled by the state manager */
2706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2713 *pMatrix = This->stateBlock->transforms[State];
2717 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2718 const WINED3DMATRIX *mat = NULL;
2721 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2722 * below means it will be recorded in a state block change, but it
2723 * works regardless where it is recorded.
2724 * If this is found to be wrong, change to StateBlock.
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2729 if (State < HIGHEST_TRANSFORMSTATE)
2731 mat = &This->updateStateBlock->transforms[State];
2733 FIXME("Unhandled transform state!!\n");
2736 multiply_matrix(&temp, mat, pMatrix);
2738 /* Apply change via set transform - will reapply to eg. lights this way */
2739 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2745 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2746 you can reference any indexes you want as long as that number max are enabled at any
2747 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2748 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2749 but when recording, just build a chain pretty much of commands to be replayed. */
2751 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2753 PLIGHTINFOEL *object = NULL;
2754 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2760 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2764 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2768 switch(pLight->Type) {
2769 case WINED3DLIGHT_POINT:
2770 case WINED3DLIGHT_SPOT:
2771 case WINED3DLIGHT_PARALLELPOINT:
2772 case WINED3DLIGHT_GLSPOT:
2773 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2776 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2777 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2778 return WINED3DERR_INVALIDCALL;
2782 case WINED3DLIGHT_DIRECTIONAL:
2783 /* Ignores attenuation */
2787 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2788 return WINED3DERR_INVALIDCALL;
2791 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2792 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2793 if(object->OriginalIndex == Index) break;
2798 TRACE("Adding new light\n");
2799 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2801 ERR("Out of memory error when allocating a light\n");
2802 return E_OUTOFMEMORY;
2804 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2805 object->glIndex = -1;
2806 object->OriginalIndex = Index;
2807 object->changed = TRUE;
2810 /* Initialize the object */
2811 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,
2812 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2813 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2814 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2815 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2816 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2817 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2819 /* Save away the information */
2820 object->OriginalParms = *pLight;
2822 switch (pLight->Type) {
2823 case WINED3DLIGHT_POINT:
2825 object->lightPosn[0] = pLight->Position.x;
2826 object->lightPosn[1] = pLight->Position.y;
2827 object->lightPosn[2] = pLight->Position.z;
2828 object->lightPosn[3] = 1.0f;
2829 object->cutoff = 180.0f;
2833 case WINED3DLIGHT_DIRECTIONAL:
2835 object->lightPosn[0] = -pLight->Direction.x;
2836 object->lightPosn[1] = -pLight->Direction.y;
2837 object->lightPosn[2] = -pLight->Direction.z;
2838 object->lightPosn[3] = 0.0;
2839 object->exponent = 0.0f;
2840 object->cutoff = 180.0f;
2843 case WINED3DLIGHT_SPOT:
2845 object->lightPosn[0] = pLight->Position.x;
2846 object->lightPosn[1] = pLight->Position.y;
2847 object->lightPosn[2] = pLight->Position.z;
2848 object->lightPosn[3] = 1.0;
2851 object->lightDirn[0] = pLight->Direction.x;
2852 object->lightDirn[1] = pLight->Direction.y;
2853 object->lightDirn[2] = pLight->Direction.z;
2854 object->lightDirn[3] = 1.0;
2857 * opengl-ish and d3d-ish spot lights use too different models for the
2858 * light "intensity" as a function of the angle towards the main light direction,
2859 * so we only can approximate very roughly.
2860 * however spot lights are rather rarely used in games (if ever used at all).
2861 * furthermore if still used, probably nobody pays attention to such details.
2863 if (pLight->Falloff == 0) {
2864 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2865 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2866 * will always be 1.0 for both of them, and we don't have to care for the
2867 * rest of the rather complex calculation
2869 object->exponent = 0;
2871 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2872 if (rho < 0.0001) rho = 0.0001f;
2873 object->exponent = -0.3/log(cos(rho/2));
2875 if (object->exponent > 128.0) {
2876 object->exponent = 128.0;
2878 object->cutoff = pLight->Phi*90/M_PI;
2884 FIXME("Unrecognized light type %d\n", pLight->Type);
2887 /* Update the live definitions if the light is currently assigned a glIndex */
2888 if (object->glIndex != -1 && !This->isRecordingState) {
2889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2894 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2895 PLIGHTINFOEL *lightInfo = NULL;
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2899 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2901 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2902 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2903 if(lightInfo->OriginalIndex == Index) break;
2907 if (lightInfo == NULL) {
2908 TRACE("Light information requested but light not defined\n");
2909 return WINED3DERR_INVALIDCALL;
2912 *pLight = lightInfo->OriginalParms;
2917 * Get / Set Light Enable
2918 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2920 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2921 PLIGHTINFOEL *lightInfo = NULL;
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2925 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2927 /* Tests show true = 128...not clear why */
2928 Enable = Enable? 128: 0;
2930 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2931 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2932 if(lightInfo->OriginalIndex == Index) break;
2935 TRACE("Found light: %p\n", lightInfo);
2937 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2938 if (lightInfo == NULL) {
2940 TRACE("Light enabled requested but light not defined, so defining one!\n");
2941 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2943 /* Search for it again! Should be fairly quick as near head of list */
2944 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2945 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2946 if(lightInfo->OriginalIndex == Index) break;
2949 if (lightInfo == NULL) {
2950 FIXME("Adding default lights has failed dismally\n");
2951 return WINED3DERR_INVALIDCALL;
2955 lightInfo->enabledChanged = TRUE;
2957 if(lightInfo->glIndex != -1) {
2958 if(!This->isRecordingState) {
2959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2962 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2963 lightInfo->glIndex = -1;
2965 TRACE("Light already disabled, nothing to do\n");
2967 lightInfo->enabled = FALSE;
2969 lightInfo->enabled = TRUE;
2970 if (lightInfo->glIndex != -1) {
2972 TRACE("Nothing to do as light was enabled\n");
2975 /* Find a free gl light */
2976 for(i = 0; i < This->maxConcurrentLights; i++) {
2977 if(This->updateStateBlock->activeLights[i] == NULL) {
2978 This->updateStateBlock->activeLights[i] = lightInfo;
2979 lightInfo->glIndex = i;
2983 if(lightInfo->glIndex == -1) {
2984 /* Our tests show that Windows returns D3D_OK in this situation, even with
2985 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2986 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2987 * as well for those lights.
2989 * TODO: Test how this affects rendering
2991 WARN("Too many concurrently active lights\n");
2995 /* i == lightInfo->glIndex */
2996 if(!This->isRecordingState) {
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3005 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3007 PLIGHTINFOEL *lightInfo = NULL;
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3011 TRACE("(%p) : for idx(%d)\n", This, Index);
3013 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3014 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3015 if(lightInfo->OriginalIndex == Index) break;
3019 if (lightInfo == NULL) {
3020 TRACE("Light enabled state requested but light not defined\n");
3021 return WINED3DERR_INVALIDCALL;
3023 /* true is 128 according to SetLightEnable */
3024 *pEnable = lightInfo->enabled ? 128 : 0;
3029 * Get / Set Clip Planes
3031 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3035 /* Validate Index */
3036 if (Index >= GL_LIMITS(clipplanes)) {
3037 TRACE("Application has requested clipplane this device doesn't support\n");
3038 return WINED3DERR_INVALIDCALL;
3041 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3043 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3044 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3045 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3046 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3047 TRACE("Application is setting old values over, nothing to do\n");
3051 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3052 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3053 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3054 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3056 /* Handle recording of state blocks */
3057 if (This->isRecordingState) {
3058 TRACE("Recording... not performing anything\n");
3062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3067 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 TRACE("(%p) : for idx %d\n", This, Index);
3071 /* Validate Index */
3072 if (Index >= GL_LIMITS(clipplanes)) {
3073 TRACE("Application has requested clipplane this device doesn't support\n");
3074 return WINED3DERR_INVALIDCALL;
3077 pPlane[0] = This->stateBlock->clipplane[Index][0];
3078 pPlane[1] = This->stateBlock->clipplane[Index][1];
3079 pPlane[2] = This->stateBlock->clipplane[Index][2];
3080 pPlane[3] = This->stateBlock->clipplane[Index][3];
3085 * Get / Set Clip Plane Status
3086 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3088 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3090 FIXME("(%p) : stub\n", This);
3091 if (NULL == pClipStatus) {
3092 return WINED3DERR_INVALIDCALL;
3094 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3095 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 FIXME("(%p) : stub\n", This);
3102 if (NULL == pClipStatus) {
3103 return WINED3DERR_INVALIDCALL;
3105 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3106 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3111 * Get / Set Material
3113 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3116 This->updateStateBlock->changed.material = TRUE;
3117 This->updateStateBlock->material = *pMaterial;
3119 /* Handle recording of state blocks */
3120 if (This->isRecordingState) {
3121 TRACE("Recording... not performing anything\n");
3125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 *pMaterial = This->updateStateBlock->material;
3132 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3133 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3134 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3135 pMaterial->Ambient.b, pMaterial->Ambient.a);
3136 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3137 pMaterial->Specular.b, pMaterial->Specular.a);
3138 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3139 pMaterial->Emissive.b, pMaterial->Emissive.a);
3140 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 IWineD3DIndexBuffer *oldIdxs;
3152 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3153 oldIdxs = This->updateStateBlock->pIndexData;
3155 This->updateStateBlock->changed.indices = TRUE;
3156 This->updateStateBlock->pIndexData = pIndexData;
3158 /* Handle recording of state blocks */
3159 if (This->isRecordingState) {
3160 TRACE("Recording... not performing anything\n");
3161 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3162 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3166 if(oldIdxs != pIndexData) {
3167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3168 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3169 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 *ppIndexData = This->stateBlock->pIndexData;
3179 /* up ref count on ppindexdata */
3181 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3182 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3184 TRACE("(%p) No index data set\n", This);
3186 TRACE("Returning %p\n", *ppIndexData);
3191 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3192 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 TRACE("(%p)->(%d)\n", This, BaseIndex);
3196 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3197 TRACE("Application is setting the old value over, nothing to do\n");
3201 This->updateStateBlock->baseVertexIndex = BaseIndex;
3203 if (This->isRecordingState) {
3204 TRACE("Recording... not performing anything\n");
3207 /* The base vertex index affects the stream sources */
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 TRACE("(%p) : base_index %p\n", This, base_index);
3216 *base_index = This->stateBlock->baseVertexIndex;
3218 TRACE("Returning %u\n", *base_index);
3224 * Get / Set Viewports
3226 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p)\n", This);
3230 This->updateStateBlock->changed.viewport = TRUE;
3231 This->updateStateBlock->viewport = *pViewport;
3233 /* Handle recording of state blocks */
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3239 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3240 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 TRACE("(%p)\n", This);
3250 *pViewport = This->stateBlock->viewport;
3255 * Get / Set Render States
3256 * TODO: Verify against dx9 definitions
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 DWORD oldValue = This->stateBlock->renderState[State];
3263 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3265 This->updateStateBlock->changed.renderState[State] = TRUE;
3266 This->updateStateBlock->renderState[State] = Value;
3268 /* Handle recording of state blocks */
3269 if (This->isRecordingState) {
3270 TRACE("Recording... not performing anything\n");
3274 /* Compared here and not before the assignment to allow proper stateblock recording */
3275 if(Value == oldValue) {
3276 TRACE("Application is setting the old value over, nothing to do\n");
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3284 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3287 *pValue = This->stateBlock->renderState[State];
3292 * Get / Set Sampler States
3293 * TODO: Verify against dx9 definitions
3296 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3300 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3301 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3303 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3304 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3307 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3308 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3309 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3312 * SetSampler is designed to allow for more than the standard up to 8 textures
3313 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3314 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3316 * http://developer.nvidia.com/object/General_FAQ.html#t6
3318 * There are two new settings for GForce
3320 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3321 * and the texture one:
3322 * GL_MAX_TEXTURE_COORDS_ARB.
3323 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3326 oldValue = This->stateBlock->samplerState[Sampler][Type];
3327 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3328 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3330 /* Handle recording of state blocks */
3331 if (This->isRecordingState) {
3332 TRACE("Recording... not performing anything\n");
3336 if(oldValue == Value) {
3337 TRACE("Application is setting the old value over, nothing to do\n");
3341 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3346 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3349 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3350 This, Sampler, debug_d3dsamplerstate(Type), Type);
3352 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3353 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3356 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3357 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3358 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3360 *Value = This->stateBlock->samplerState[Sampler][Type];
3361 TRACE("(%p) : Returning %#x\n", This, *Value);
3366 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3369 This->updateStateBlock->changed.scissorRect = TRUE;
3370 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3371 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3374 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3376 if(This->isRecordingState) {
3377 TRACE("Recording... not performing anything\n");
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3386 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3389 *pRect = This->updateStateBlock->scissorRect;
3390 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3394 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3396 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3398 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3400 This->updateStateBlock->vertexDecl = pDecl;
3401 This->updateStateBlock->changed.vertexDecl = TRUE;
3403 if (This->isRecordingState) {
3404 TRACE("Recording... not performing anything\n");
3406 } else if(pDecl == oldDecl) {
3407 /* Checked after the assignment to allow proper stateblock recording */
3408 TRACE("Application is setting the old declaration over, nothing to do\n");
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3416 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3419 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3421 *ppDecl = This->stateBlock->vertexDecl;
3422 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3426 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3428 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3430 This->updateStateBlock->vertexShader = pShader;
3431 This->updateStateBlock->changed.vertexShader = TRUE;
3433 if (This->isRecordingState) {
3434 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3435 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3436 TRACE("Recording... not performing anything\n");
3438 } else if(oldShader == pShader) {
3439 /* Checked here to allow proper stateblock recording */
3440 TRACE("App is setting the old shader over, nothing to do\n");
3444 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3445 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3446 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3453 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 if (NULL == ppShader) {
3457 return WINED3DERR_INVALIDCALL;
3459 *ppShader = This->stateBlock->vertexShader;
3460 if( NULL != *ppShader)
3461 IWineD3DVertexShader_AddRef(*ppShader);
3463 TRACE("(%p) : returning %p\n", This, *ppShader);
3467 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3468 IWineD3DDevice *iface,
3470 CONST BOOL *srcData,
3473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3474 int i, cnt = min(count, MAX_CONST_B - start);
3476 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3477 iface, srcData, start, count);
3479 if (srcData == NULL || cnt < 0)
3480 return WINED3DERR_INVALIDCALL;
3482 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3483 for (i = 0; i < cnt; i++)
3484 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3486 for (i = start; i < cnt + start; ++i) {
3487 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3490 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3495 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3496 IWineD3DDevice *iface,
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3502 int cnt = min(count, MAX_CONST_B - start);
3504 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3505 iface, dstData, start, count);
3507 if (dstData == NULL || cnt < 0)
3508 return WINED3DERR_INVALIDCALL;
3510 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3514 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3515 IWineD3DDevice *iface,
3520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3521 int i, cnt = min(count, MAX_CONST_I - start);
3523 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3524 iface, srcData, start, count);
3526 if (srcData == NULL || cnt < 0)
3527 return WINED3DERR_INVALIDCALL;
3529 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3530 for (i = 0; i < cnt; i++)
3531 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3532 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3534 for (i = start; i < cnt + start; ++i) {
3535 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3538 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3543 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3544 IWineD3DDevice *iface,
3549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 int cnt = min(count, MAX_CONST_I - start);
3552 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3553 iface, dstData, start, count);
3555 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3556 return WINED3DERR_INVALIDCALL;
3558 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3562 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3563 IWineD3DDevice *iface,
3565 CONST float *srcData,
3568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3572 iface, srcData, start, count);
3574 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3575 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3576 return WINED3DERR_INVALIDCALL;
3578 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3580 for (i = 0; i < count; i++)
3581 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3582 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3585 if (!This->isRecordingState)
3587 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3591 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3592 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3597 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3598 IWineD3DDevice *iface,
3603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3604 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3606 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3607 iface, dstData, start, count);
3609 if (dstData == NULL || cnt < 0)
3610 return WINED3DERR_INVALIDCALL;
3612 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3616 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3618 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3623 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3624 int i = This->rev_tex_unit_map[unit];
3625 int j = This->texUnitMap[stage];
3627 This->texUnitMap[stage] = unit;
3628 if (i != -1 && i != stage) {
3629 This->texUnitMap[i] = -1;
3632 This->rev_tex_unit_map[unit] = stage;
3633 if (j != -1 && j != unit) {
3634 This->rev_tex_unit_map[j] = -1;
3638 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3641 This->fixed_function_usage_map = 0;
3642 for (i = 0; i < MAX_TEXTURES; ++i) {
3643 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3644 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3645 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3646 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3647 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3648 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3649 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3650 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3652 if (color_op == WINED3DTOP_DISABLE) {
3653 /* Not used, and disable higher stages */
3657 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3658 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3659 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3660 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3661 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3662 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3663 This->fixed_function_usage_map |= (1 << i);
3666 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3667 This->fixed_function_usage_map |= (1 << (i + 1));
3672 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3675 device_update_fixed_function_usage_map(This);
3677 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3678 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3679 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3680 if (!(This->fixed_function_usage_map & (1 << i))) continue;
3682 if (This->texUnitMap[i] != i) {
3683 device_map_stage(This, i, i);
3684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3685 markTextureStagesDirty(This, i);
3691 /* Now work out the mapping */
3693 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3694 if (!(This->fixed_function_usage_map & (1 << i))) continue;
3696 if (This->texUnitMap[i] != tex) {
3697 device_map_stage(This, i, tex);
3698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3699 markTextureStagesDirty(This, i);
3706 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3707 const DWORD *sampler_tokens =
3708 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3711 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3712 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3713 device_map_stage(This, i, i);
3714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3715 if (i < MAX_TEXTURES) {
3716 markTextureStagesDirty(This, i);
3722 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3723 const DWORD *vshader_sampler_tokens, int unit)
3725 int current_mapping = This->rev_tex_unit_map[unit];
3727 if (current_mapping == -1) {
3728 /* Not currently used */
3732 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3733 /* Used by a fragment sampler */
3735 if (!pshader_sampler_tokens) {
3736 /* No pixel shader, check fixed function */
3737 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3740 /* Pixel shader, check the shader's sampler map */
3741 return !pshader_sampler_tokens[current_mapping];
3744 /* Used by a vertex sampler */
3745 return !vshader_sampler_tokens[current_mapping];
3748 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3749 const DWORD *vshader_sampler_tokens =
3750 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3751 const DWORD *pshader_sampler_tokens = NULL;
3752 int start = GL_LIMITS(combined_samplers) - 1;
3756 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3758 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3759 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3760 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3763 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3764 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3765 if (vshader_sampler_tokens[i]) {
3766 if (This->texUnitMap[vsampler_idx] != -1) {
3767 /* Already mapped somewhere */
3771 while (start >= 0) {
3772 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3773 device_map_stage(This, vsampler_idx, start);
3774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3786 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3787 BOOL vs = use_vs(This->stateBlock);
3788 BOOL ps = use_ps(This->stateBlock);
3791 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3792 * that would be really messy and require shader recompilation
3793 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3794 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3797 device_map_psamplers(This);
3799 device_map_fixed_function_samplers(This);
3803 device_map_vsamplers(This, ps);
3807 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3810 This->updateStateBlock->pixelShader = pShader;
3811 This->updateStateBlock->changed.pixelShader = TRUE;
3813 /* Handle recording of state blocks */
3814 if (This->isRecordingState) {
3815 TRACE("Recording... not performing anything\n");
3818 if (This->isRecordingState) {
3819 TRACE("Recording... not performing anything\n");
3820 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3821 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3825 if(pShader == oldShader) {
3826 TRACE("App is setting the old pixel shader over, nothing to do\n");
3830 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3831 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3833 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3839 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 if (NULL == ppShader) {
3843 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3844 return WINED3DERR_INVALIDCALL;
3847 *ppShader = This->stateBlock->pixelShader;
3848 if (NULL != *ppShader) {
3849 IWineD3DPixelShader_AddRef(*ppShader);
3851 TRACE("(%p) : returning %p\n", This, *ppShader);
3855 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3856 IWineD3DDevice *iface,
3858 CONST BOOL *srcData,
3861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3862 int i, cnt = min(count, MAX_CONST_B - start);
3864 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3865 iface, srcData, start, count);
3867 if (srcData == NULL || cnt < 0)
3868 return WINED3DERR_INVALIDCALL;
3870 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3871 for (i = 0; i < cnt; i++)
3872 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3874 for (i = start; i < cnt + start; ++i) {
3875 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3878 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3883 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3884 IWineD3DDevice *iface,
3889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3890 int cnt = min(count, MAX_CONST_B - start);
3892 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3893 iface, dstData, start, count);
3895 if (dstData == NULL || cnt < 0)
3896 return WINED3DERR_INVALIDCALL;
3898 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3902 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3903 IWineD3DDevice *iface,
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 int i, cnt = min(count, MAX_CONST_I - start);
3911 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3912 iface, srcData, start, count);
3914 if (srcData == NULL || cnt < 0)
3915 return WINED3DERR_INVALIDCALL;
3917 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3918 for (i = 0; i < cnt; i++)
3919 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3920 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3922 for (i = start; i < cnt + start; ++i) {
3923 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3926 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3931 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3932 IWineD3DDevice *iface,
3937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3938 int cnt = min(count, MAX_CONST_I - start);
3940 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3941 iface, dstData, start, count);
3943 if (dstData == NULL || cnt < 0)
3944 return WINED3DERR_INVALIDCALL;
3946 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3950 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3951 IWineD3DDevice *iface,
3953 CONST float *srcData,
3956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3959 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3960 iface, srcData, start, count);
3962 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3963 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3964 return WINED3DERR_INVALIDCALL;
3966 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3968 for (i = 0; i < count; i++)
3969 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3970 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3973 if (!This->isRecordingState)
3975 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3979 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3980 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3985 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3986 IWineD3DDevice *iface,
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3994 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3995 iface, dstData, start, count);
3997 if (dstData == NULL || cnt < 0)
3998 return WINED3DERR_INVALIDCALL;
4000 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4004 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4005 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4006 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4008 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4010 DWORD DestFVF = dest->fvf;
4012 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4016 if (lpStrideData->u.s.normal.lpData) {
4017 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4020 if (lpStrideData->u.s.position.lpData == NULL) {
4021 ERR("Source has no position mask\n");
4022 return WINED3DERR_INVALIDCALL;
4025 /* We might access VBOs from this code, so hold the lock */
4028 if (dest->resource.allocatedMemory == NULL) {
4029 /* This may happen if we do direct locking into a vbo. Unlikely,
4030 * but theoretically possible(ddraw processvertices test)
4032 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4033 if(!dest->resource.allocatedMemory) {
4035 ERR("Out of memory\n");
4036 return E_OUTOFMEMORY;
4040 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4041 checkGLcall("glBindBufferARB");
4042 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4044 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4046 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4047 checkGLcall("glUnmapBufferARB");
4051 /* Get a pointer into the destination vbo(create one if none exists) and
4052 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4054 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4055 dest->Flags |= VBFLAG_CREATEVBO;
4056 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4060 unsigned char extrabytes = 0;
4061 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4062 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4063 * this may write 4 extra bytes beyond the area that should be written
4065 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4066 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4067 if(!dest_conv_addr) {
4068 ERR("Out of memory\n");
4069 /* Continue without storing converted vertices */
4071 dest_conv = dest_conv_addr;
4075 * a) WINED3DRS_CLIPPING is enabled
4076 * b) WINED3DVOP_CLIP is passed
4078 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4079 static BOOL warned = FALSE;
4081 * The clipping code is not quite correct. Some things need
4082 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4083 * so disable clipping for now.
4084 * (The graphics in Half-Life are broken, and my processvertices
4085 * test crashes with IDirect3DDevice3)
4091 FIXME("Clipping is broken and disabled for now\n");
4093 } else doClip = FALSE;
4094 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4096 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4099 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4100 WINED3DTS_PROJECTION,
4102 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4103 WINED3DTS_WORLDMATRIX(0),
4106 TRACE("View mat:\n");
4107 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);
4108 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);
4109 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);
4110 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);
4112 TRACE("Proj mat:\n");
4113 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);
4114 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);
4115 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);
4116 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);
4118 TRACE("World mat:\n");
4119 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);
4120 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);
4121 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);
4122 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);
4124 /* Get the viewport */
4125 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4126 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4127 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4129 multiply_matrix(&mat,&view_mat,&world_mat);
4130 multiply_matrix(&mat,&proj_mat,&mat);
4132 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4134 for (i = 0; i < dwCount; i+= 1) {
4135 unsigned int tex_index;
4137 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4138 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4139 /* The position first */
4141 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4143 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4145 /* Multiplication with world, view and projection matrix */
4146 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);
4147 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);
4148 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);
4149 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);
4151 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4153 /* WARNING: The following things are taken from d3d7 and were not yet checked
4154 * against d3d8 or d3d9!
4157 /* Clipping conditions: From msdn
4159 * A vertex is clipped if it does not match the following requirements
4163 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4165 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4166 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4171 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4172 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4175 /* "Normal" viewport transformation (not clipped)
4176 * 1) The values are divided by rhw
4177 * 2) The y axis is negative, so multiply it with -1
4178 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4179 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4180 * 4) Multiply x with Width/2 and add Width/2
4181 * 5) The same for the height
4182 * 6) Add the viewpoint X and Y to the 2D coordinates and
4183 * The minimum Z value to z
4184 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4186 * Well, basically it's simply a linear transformation into viewport
4198 z *= vp.MaxZ - vp.MinZ;
4200 x += vp.Width / 2 + vp.X;
4201 y += vp.Height / 2 + vp.Y;
4206 /* That vertex got clipped
4207 * Contrary to OpenGL it is not dropped completely, it just
4208 * undergoes a different calculation.
4210 TRACE("Vertex got clipped\n");
4217 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4218 * outside of the main vertex buffer memory. That needs some more
4223 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4226 ( (float *) dest_ptr)[0] = x;
4227 ( (float *) dest_ptr)[1] = y;
4228 ( (float *) dest_ptr)[2] = z;
4229 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4231 dest_ptr += 3 * sizeof(float);
4233 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4234 dest_ptr += sizeof(float);
4239 ( (float *) dest_conv)[0] = x * w;
4240 ( (float *) dest_conv)[1] = y * w;
4241 ( (float *) dest_conv)[2] = z * w;
4242 ( (float *) dest_conv)[3] = w;
4244 dest_conv += 3 * sizeof(float);
4246 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4247 dest_conv += sizeof(float);
4251 if (DestFVF & WINED3DFVF_PSIZE) {
4252 dest_ptr += sizeof(DWORD);
4253 if(dest_conv) dest_conv += sizeof(DWORD);
4255 if (DestFVF & WINED3DFVF_NORMAL) {
4256 const float *normal =
4257 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4258 /* AFAIK this should go into the lighting information */
4259 FIXME("Didn't expect the destination to have a normal\n");
4260 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4262 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4266 if (DestFVF & WINED3DFVF_DIFFUSE) {
4267 const DWORD *color_d =
4268 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4270 static BOOL warned = FALSE;
4273 ERR("No diffuse color in source, but destination has one\n");
4277 *( (DWORD *) dest_ptr) = 0xffffffff;
4278 dest_ptr += sizeof(DWORD);
4281 *( (DWORD *) dest_conv) = 0xffffffff;
4282 dest_conv += sizeof(DWORD);
4286 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4288 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4289 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4290 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4291 dest_conv += sizeof(DWORD);
4296 if (DestFVF & WINED3DFVF_SPECULAR) {
4297 /* What's the color value in the feedback buffer? */
4298 const DWORD *color_s =
4299 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4301 static BOOL warned = FALSE;
4304 ERR("No specular color in source, but destination has one\n");
4308 *( (DWORD *) dest_ptr) = 0xFF000000;
4309 dest_ptr += sizeof(DWORD);
4312 *( (DWORD *) dest_conv) = 0xFF000000;
4313 dest_conv += sizeof(DWORD);
4317 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4319 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4320 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4321 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4322 dest_conv += sizeof(DWORD);
4327 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4328 const float *tex_coord =
4329 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4330 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4332 ERR("No source texture, but destination requests one\n");
4333 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4334 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4337 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4339 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4346 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4347 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4348 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4349 dwCount * get_flexible_vertex_size(DestFVF),
4351 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4352 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4359 #undef copy_and_next
4361 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4363 WineDirect3DVertexStridedData strided;
4364 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4365 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4368 ERR("Output vertex declaration not implemented yet\n");
4371 /* Need any context to write to the vbo. */
4372 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4374 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4375 * control the streamIsUP flag, thus restore it afterwards.
4377 This->stateBlock->streamIsUP = FALSE;
4378 memset(&strided, 0, sizeof(strided));
4379 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4380 This->stateBlock->streamIsUP = streamWasUP;
4382 if(vbo || SrcStartIndex) {
4384 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4385 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4387 * Also get the start index in, but only loop over all elements if there's something to add at all.
4389 #define FIXSRC(type) \
4390 if(strided.u.s.type.VBO) { \
4391 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4392 strided.u.s.type.VBO = 0; \
4393 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4395 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4399 if(strided.u.s.type.lpData) { \
4400 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4403 FIXSRC(blendWeights);
4404 FIXSRC(blendMatrixIndices);
4409 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4410 FIXSRC(texCoords[i]);
4423 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4427 * Get / Set Texture Stage States
4428 * TODO: Verify against dx9 definitions
4430 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4434 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4436 if (Stage >= MAX_TEXTURES) {
4437 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4441 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4442 This->updateStateBlock->textureState[Stage][Type] = Value;
4444 if (This->isRecordingState) {
4445 TRACE("Recording... not performing anything\n");
4449 /* Checked after the assignments to allow proper stateblock recording */
4450 if(oldValue == Value) {
4451 TRACE("App is setting the old value over, nothing to do\n");
4455 if(Stage > This->stateBlock->lowest_disabled_stage &&
4456 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4457 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4458 * Changes in other states are important on disabled stages too
4463 if(Type == WINED3DTSS_COLOROP) {
4466 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4467 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4468 * they have to be disabled
4470 * The current stage is dirtified below.
4472 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4473 TRACE("Additionally dirtifying stage %d\n", i);
4474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4476 This->stateBlock->lowest_disabled_stage = Stage;
4477 TRACE("New lowest disabled: %d\n", Stage);
4478 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4479 /* Previously disabled stage enabled. Stages above it may need enabling
4480 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4481 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4483 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4486 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4487 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4490 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4493 This->stateBlock->lowest_disabled_stage = i;
4494 TRACE("New lowest disabled: %d\n", i);
4498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4506 *pValue = This->updateStateBlock->textureState[Stage][Type];
4513 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4515 IWineD3DBaseTexture *oldTexture;
4517 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4519 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4520 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4523 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4524 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4525 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4528 oldTexture = This->updateStateBlock->textures[Stage];
4530 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4531 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4533 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4534 return WINED3DERR_INVALIDCALL;
4537 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4538 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4540 This->updateStateBlock->changed.textures[Stage] = TRUE;
4541 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4542 This->updateStateBlock->textures[Stage] = pTexture;
4544 /* Handle recording of state blocks */
4545 if (This->isRecordingState) {
4546 TRACE("Recording... not performing anything\n");
4550 if(oldTexture == pTexture) {
4551 TRACE("App is setting the same texture again, nothing to do\n");
4555 /** NOTE: MSDN says that setTexture increases the reference count,
4556 * and that the application must set the texture back to null (or have a leaky application),
4557 * This means we should pass the refcount up to the parent
4558 *******************************/
4559 if (NULL != This->updateStateBlock->textures[Stage]) {
4560 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4561 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4563 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4564 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4565 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4566 * so the COLOROP and ALPHAOP have to be dirtified.
4568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4571 if(bindCount == 1) {
4572 new->baseTexture.sampler = Stage;
4574 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4578 if (NULL != oldTexture) {
4579 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4580 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4582 IWineD3DBaseTexture_Release(oldTexture);
4583 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4588 if(bindCount && old->baseTexture.sampler == Stage) {
4590 /* Have to do a search for the other sampler(s) where the texture is bound to
4591 * Shouldn't happen as long as apps bind a texture only to one stage
4593 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4594 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4595 if(This->updateStateBlock->textures[i] == oldTexture) {
4596 old->baseTexture.sampler = i;
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4608 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4611 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4613 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4614 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4617 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4618 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4619 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4622 *ppTexture=This->stateBlock->textures[Stage];
4624 IWineD3DBaseTexture_AddRef(*ppTexture);
4626 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4634 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4635 IWineD3DSurface **ppBackBuffer) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4637 IWineD3DSwapChain *swapChain;
4640 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4642 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4643 if (hr == WINED3D_OK) {
4644 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4645 IWineD3DSwapChain_Release(swapChain);
4647 *ppBackBuffer = NULL;
4652 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4654 WARN("(%p) : stub, calling idirect3d for now\n", This);
4655 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4658 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 IWineD3DSwapChain *swapChain;
4663 if(iSwapChain > 0) {
4664 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4665 if (hr == WINED3D_OK) {
4666 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4667 IWineD3DSwapChain_Release(swapChain);
4669 FIXME("(%p) Error getting display mode\n", This);
4672 /* Don't read the real display mode,
4673 but return the stored mode instead. X11 can't change the color
4674 depth, and some apps are pretty angry if they SetDisplayMode from
4675 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4677 Also don't relay to the swapchain because with ddraw it's possible
4678 that there isn't a swapchain at all */
4679 pMode->Width = This->ddraw_width;
4680 pMode->Height = This->ddraw_height;
4681 pMode->Format = This->ddraw_format;
4682 pMode->RefreshRate = 0;
4690 * Stateblock related functions
4693 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 IWineD3DStateBlockImpl *object;
4696 HRESULT temp_result;
4699 TRACE("(%p)\n", This);
4701 if (This->isRecordingState) {
4702 return WINED3DERR_INVALIDCALL;
4705 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4706 if (NULL == object ) {
4707 FIXME("(%p)Error allocating memory for stateblock\n", This);
4708 return E_OUTOFMEMORY;
4710 TRACE("(%p) created object %p\n", This, object);
4711 object->wineD3DDevice= This;
4712 /** FIXME: object->parent = parent; **/
4713 object->parent = NULL;
4714 object->blockType = WINED3DSBT_RECORDED;
4716 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4718 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4719 list_init(&object->lightMap[i]);
4722 temp_result = allocate_shader_constants(object);
4723 if (WINED3D_OK != temp_result)
4726 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4727 This->updateStateBlock = object;
4728 This->isRecordingState = TRUE;
4730 TRACE("(%p) recording stateblock %p\n",This , object);
4734 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4739 if (!This->isRecordingState) {
4740 WARN("(%p) not recording! returning error\n", This);
4741 *ppStateBlock = NULL;
4742 return WINED3DERR_INVALIDCALL;
4745 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4746 if(object->changed.renderState[i]) {
4747 object->contained_render_states[object->num_contained_render_states] = i;
4748 object->num_contained_render_states++;
4751 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4752 if(object->changed.transform[i]) {
4753 object->contained_transform_states[object->num_contained_transform_states] = i;
4754 object->num_contained_transform_states++;
4757 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4758 if(object->changed.vertexShaderConstantsF[i]) {
4759 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4760 object->num_contained_vs_consts_f++;
4763 for(i = 0; i < MAX_CONST_I; i++) {
4764 if (object->changed.vertexShaderConstantsI & (1 << i))
4766 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4767 object->num_contained_vs_consts_i++;
4770 for(i = 0; i < MAX_CONST_B; i++) {
4771 if (object->changed.vertexShaderConstantsB & (1 << i))
4773 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4774 object->num_contained_vs_consts_b++;
4777 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4779 if (object->changed.pixelShaderConstantsF[i])
4781 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4782 ++object->num_contained_ps_consts_f;
4785 for(i = 0; i < MAX_CONST_I; i++) {
4786 if (object->changed.pixelShaderConstantsI & (1 << i))
4788 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4789 object->num_contained_ps_consts_i++;
4792 for(i = 0; i < MAX_CONST_B; i++) {
4793 if (object->changed.pixelShaderConstantsB & (1 << i))
4795 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4796 object->num_contained_ps_consts_b++;
4799 for(i = 0; i < MAX_TEXTURES; i++) {
4800 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4801 if(object->changed.textureState[i][j]) {
4802 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4803 object->contained_tss_states[object->num_contained_tss_states].state = j;
4804 object->num_contained_tss_states++;
4808 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4809 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4810 if(object->changed.samplerState[i][j]) {
4811 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4812 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4813 object->num_contained_sampler_states++;
4818 *ppStateBlock = (IWineD3DStateBlock*) object;
4819 This->isRecordingState = FALSE;
4820 This->updateStateBlock = This->stateBlock;
4821 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4822 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4823 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4828 * Scene related functions
4830 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4831 /* At the moment we have no need for any functionality at the beginning
4833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4834 TRACE("(%p)\n", This);
4837 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4838 return WINED3DERR_INVALIDCALL;
4840 This->inScene = TRUE;
4844 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 TRACE("(%p)\n", This);
4848 if(!This->inScene) {
4849 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4850 return WINED3DERR_INVALIDCALL;
4853 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4854 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4856 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4860 This->inScene = FALSE;
4864 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4865 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4866 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4868 IWineD3DSwapChain *swapChain = NULL;
4870 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4872 TRACE("(%p) Presenting the frame\n", This);
4874 for(i = 0 ; i < swapchains ; i ++) {
4876 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4877 TRACE("presentinng chain %d, %p\n", i, swapChain);
4878 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4879 IWineD3DSwapChain_Release(swapChain);
4885 /* Not called from the VTable (internal subroutine) */
4886 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4887 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4888 float Z, DWORD Stencil) {
4889 GLbitfield glMask = 0;
4891 WINED3DRECT curRect;
4893 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4894 UINT drawable_width, drawable_height;
4895 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4896 IWineD3DSwapChainImpl *swapchain = NULL;
4898 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4899 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4900 * for the cleared parts, and the untouched parts.
4902 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4903 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4904 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4905 * checking all this if the dest surface is in the drawable anyway.
4907 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4909 if(vp->X != 0 || vp->Y != 0 ||
4910 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4911 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4914 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4915 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4916 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4917 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4918 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4921 if(Count > 0 && pRects && (
4922 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4923 pRects[0].x2 < target->currentDesc.Width ||
4924 pRects[0].y2 < target->currentDesc.Height)) {
4925 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4932 target->get_drawable_size(target, &drawable_width, &drawable_height);
4934 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4937 /* Only set the values up once, as they are not changing */
4938 if (Flags & WINED3DCLEAR_STENCIL) {
4939 glClearStencil(Stencil);
4940 checkGLcall("glClearStencil");
4941 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4942 glStencilMask(0xFFFFFFFF);
4945 if (Flags & WINED3DCLEAR_ZBUFFER) {
4946 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4947 glDepthMask(GL_TRUE);
4949 checkGLcall("glClearDepth");
4950 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4953 if (vp->X != 0 || vp->Y != 0 ||
4954 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4955 surface_load_ds_location(This->stencilBufferTarget, location);
4957 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4958 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4959 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4960 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4961 surface_load_ds_location(This->stencilBufferTarget, location);
4963 else if (Count > 0 && pRects && (
4964 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4965 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4966 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4967 surface_load_ds_location(This->stencilBufferTarget, location);
4971 if (Flags & WINED3DCLEAR_TARGET) {
4972 TRACE("Clearing screen with glClear to color %x\n", Color);
4973 glClearColor(D3DCOLOR_R(Color),
4977 checkGLcall("glClearColor");
4979 /* Clear ALL colors! */
4980 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4981 glMask = glMask | GL_COLOR_BUFFER_BIT;
4984 vp_rect.left = vp->X;
4985 vp_rect.top = vp->Y;
4986 vp_rect.right = vp->X + vp->Width;
4987 vp_rect.bottom = vp->Y + vp->Height;
4988 if (!(Count > 0 && pRects)) {
4989 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4990 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4992 if(This->render_offscreen) {
4993 glScissor(vp_rect.left, vp_rect.top,
4994 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4996 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4997 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4999 checkGLcall("glScissor");
5001 checkGLcall("glClear");
5003 /* Now process each rect in turn */
5004 for (i = 0; i < Count; i++) {
5005 /* Note gl uses lower left, width/height */
5006 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5007 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5008 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5010 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5011 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5012 curRect.x1, (target->currentDesc.Height - curRect.y2),
5013 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5015 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5016 * The rectangle is not cleared, no error is returned, but further rectanlges are
5017 * still cleared if they are valid
5019 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5020 TRACE("Rectangle with negative dimensions, ignoring\n");
5024 if(This->render_offscreen) {
5025 glScissor(curRect.x1, curRect.y1,
5026 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5028 glScissor(curRect.x1, drawable_height - curRect.y2,
5029 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5031 checkGLcall("glScissor");
5034 checkGLcall("glClear");
5038 /* Restore the old values (why..?) */
5039 if (Flags & WINED3DCLEAR_STENCIL) {
5040 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5042 if (Flags & WINED3DCLEAR_TARGET) {
5043 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5044 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5045 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5046 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5047 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5049 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5050 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5052 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5054 if (Flags & WINED3DCLEAR_ZBUFFER) {
5055 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5056 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5057 surface_modify_ds_location(This->stencilBufferTarget, location);
5062 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5063 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5066 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5072 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5073 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5075 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5077 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5078 Count, pRects, Flags, Color, Z, Stencil);
5080 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5081 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5082 /* TODO: What about depth stencil buffers without stencil bits? */
5083 return WINED3DERR_INVALIDCALL;
5086 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5092 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5093 UINT PrimitiveCount) {
5095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5097 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5098 debug_d3dprimitivetype(PrimitiveType),
5099 StartVertex, PrimitiveCount);
5101 if(!This->stateBlock->vertexDecl) {
5102 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5103 return WINED3DERR_INVALIDCALL;
5106 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5107 if(This->stateBlock->streamIsUP) {
5108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5109 This->stateBlock->streamIsUP = FALSE;
5112 if(This->stateBlock->loadBaseVertexIndex != 0) {
5113 This->stateBlock->loadBaseVertexIndex = 0;
5114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5116 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5117 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5118 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5122 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5123 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5124 WINED3DPRIMITIVETYPE PrimitiveType,
5125 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 IWineD3DIndexBuffer *pIB;
5130 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5133 pIB = This->stateBlock->pIndexData;
5135 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5136 * without an index buffer set. (The first time at least...)
5137 * D3D8 simply dies, but I doubt it can do much harm to return
5138 * D3DERR_INVALIDCALL there as well. */
5139 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5140 return WINED3DERR_INVALIDCALL;
5143 if(!This->stateBlock->vertexDecl) {
5144 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5145 return WINED3DERR_INVALIDCALL;
5148 if(This->stateBlock->streamIsUP) {
5149 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5150 This->stateBlock->streamIsUP = FALSE;
5152 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5154 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5155 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5156 minIndex, NumVertices, startIndex, primCount);
5158 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5159 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5165 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5166 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5170 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5171 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5176 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5177 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5178 UINT VertexStreamZeroStride) {
5179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5180 IWineD3DVertexBuffer *vb;
5182 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5183 debug_d3dprimitivetype(PrimitiveType),
5184 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5186 if(!This->stateBlock->vertexDecl) {
5187 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5188 return WINED3DERR_INVALIDCALL;
5191 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5192 vb = This->stateBlock->streamSource[0];
5193 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5194 if(vb) IWineD3DVertexBuffer_Release(vb);
5195 This->stateBlock->streamOffset[0] = 0;
5196 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5197 This->stateBlock->streamIsUP = TRUE;
5198 This->stateBlock->loadBaseVertexIndex = 0;
5200 /* TODO: Only mark dirty if drawing from a different UP address */
5201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5203 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5204 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5206 /* MSDN specifies stream zero settings must be set to NULL */
5207 This->stateBlock->streamStride[0] = 0;
5208 This->stateBlock->streamSource[0] = NULL;
5210 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5211 * the new stream sources or use UP drawing again
5216 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5217 UINT MinVertexIndex, UINT NumVertices,
5218 UINT PrimitiveCount, CONST void* pIndexData,
5219 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5220 UINT VertexStreamZeroStride) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 IWineD3DVertexBuffer *vb;
5224 IWineD3DIndexBuffer *ib;
5226 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5227 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5228 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5229 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5231 if(!This->stateBlock->vertexDecl) {
5232 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5233 return WINED3DERR_INVALIDCALL;
5236 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5242 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5243 vb = This->stateBlock->streamSource[0];
5244 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5245 if(vb) IWineD3DVertexBuffer_Release(vb);
5246 This->stateBlock->streamIsUP = TRUE;
5247 This->stateBlock->streamOffset[0] = 0;
5248 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5250 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5251 This->stateBlock->baseVertexIndex = 0;
5252 This->stateBlock->loadBaseVertexIndex = 0;
5253 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5257 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5259 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5260 This->stateBlock->streamSource[0] = NULL;
5261 This->stateBlock->streamStride[0] = 0;
5262 ib = This->stateBlock->pIndexData;
5264 IWineD3DIndexBuffer_Release(ib);
5265 This->stateBlock->pIndexData = NULL;
5267 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5268 * SetStreamSource to specify a vertex buffer
5274 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5275 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5276 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5280 /* Mark the state dirty until we have nicer tracking
5281 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5286 This->stateBlock->baseVertexIndex = 0;
5287 This->up_strided = DrawPrimStrideData;
5288 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5289 This->up_strided = NULL;
5293 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5294 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5295 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5296 WINED3DFORMAT IndexDataFormat)
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5299 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5301 /* Mark the state dirty until we have nicer tracking
5302 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5307 This->stateBlock->streamIsUP = TRUE;
5308 This->stateBlock->baseVertexIndex = 0;
5309 This->up_strided = DrawPrimStrideData;
5310 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5311 This->up_strided = NULL;
5315 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5316 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5317 * not callable by the app directly no parameter validation checks are needed here.
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5320 WINED3DLOCKED_BOX src;
5321 WINED3DLOCKED_BOX dst;
5323 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5325 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5326 * dirtification to improve loading performance.
5328 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5329 if(FAILED(hr)) return hr;
5330 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5332 IWineD3DVolume_UnlockBox(pSourceVolume);
5336 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5338 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5340 IWineD3DVolume_UnlockBox(pSourceVolume);
5342 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5347 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5348 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 HRESULT hr = WINED3D_OK;
5351 WINED3DRESOURCETYPE sourceType;
5352 WINED3DRESOURCETYPE destinationType;
5355 /* TODO: think about moving the code into IWineD3DBaseTexture */
5357 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5359 /* verify that the source and destination textures aren't NULL */
5360 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5361 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5362 This, pSourceTexture, pDestinationTexture);
5363 hr = WINED3DERR_INVALIDCALL;
5366 if (pSourceTexture == pDestinationTexture) {
5367 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5368 This, pSourceTexture, pDestinationTexture);
5369 hr = WINED3DERR_INVALIDCALL;
5371 /* Verify that the source and destination textures are the same type */
5372 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5373 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5375 if (sourceType != destinationType) {
5376 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5378 hr = WINED3DERR_INVALIDCALL;
5381 /* check that both textures have the identical numbers of levels */
5382 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5383 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5384 hr = WINED3DERR_INVALIDCALL;
5387 if (WINED3D_OK == hr) {
5389 /* Make sure that the destination texture is loaded */
5390 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5392 /* Update every surface level of the texture */
5393 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5395 switch (sourceType) {
5396 case WINED3DRTYPE_TEXTURE:
5398 IWineD3DSurface *srcSurface;
5399 IWineD3DSurface *destSurface;
5401 for (i = 0 ; i < levels ; ++i) {
5402 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5403 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5404 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5405 IWineD3DSurface_Release(srcSurface);
5406 IWineD3DSurface_Release(destSurface);
5407 if (WINED3D_OK != hr) {
5408 WARN("(%p) : Call to update surface failed\n", This);
5414 case WINED3DRTYPE_CUBETEXTURE:
5416 IWineD3DSurface *srcSurface;
5417 IWineD3DSurface *destSurface;
5418 WINED3DCUBEMAP_FACES faceType;
5420 for (i = 0 ; i < levels ; ++i) {
5421 /* Update each cube face */
5422 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5423 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5424 if (WINED3D_OK != hr) {
5425 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5427 TRACE("Got srcSurface %p\n", srcSurface);
5429 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5430 if (WINED3D_OK != hr) {
5431 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5433 TRACE("Got desrSurface %p\n", destSurface);
5435 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5436 IWineD3DSurface_Release(srcSurface);
5437 IWineD3DSurface_Release(destSurface);
5438 if (WINED3D_OK != hr) {
5439 WARN("(%p) : Call to update surface failed\n", This);
5447 case WINED3DRTYPE_VOLUMETEXTURE:
5449 IWineD3DVolume *srcVolume = NULL;
5450 IWineD3DVolume *destVolume = NULL;
5452 for (i = 0 ; i < levels ; ++i) {
5453 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5454 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5455 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5456 IWineD3DVolume_Release(srcVolume);
5457 IWineD3DVolume_Release(destVolume);
5458 if (WINED3D_OK != hr) {
5459 WARN("(%p) : Call to update volume failed\n", This);
5467 FIXME("(%p) : Unsupported source and destination type\n", This);
5468 hr = WINED3DERR_INVALIDCALL;
5475 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5476 IWineD3DSwapChain *swapChain;
5478 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5479 if(hr == WINED3D_OK) {
5480 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5481 IWineD3DSwapChain_Release(swapChain);
5486 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5488 IWineD3DBaseTextureImpl *texture;
5489 const struct GlPixelFormatDesc *gl_info;
5492 TRACE("(%p) : %p\n", This, pNumPasses);
5494 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5495 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5496 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5497 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5499 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5500 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5501 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5504 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5505 if(!texture) continue;
5506 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5507 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5509 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5510 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5513 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5514 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5517 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5518 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5519 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5524 /* return a sensible default */
5527 TRACE("returning D3D_OK\n");
5531 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5535 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5536 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5537 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5538 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5543 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5547 PALETTEENTRY **palettes;
5549 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5551 if (PaletteNumber >= MAX_PALETTES) {
5552 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5553 return WINED3DERR_INVALIDCALL;
5556 if (PaletteNumber >= This->NumberOfPalettes) {
5557 NewSize = This->NumberOfPalettes;
5560 } while(PaletteNumber >= NewSize);
5561 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5563 ERR("Out of memory!\n");
5564 return E_OUTOFMEMORY;
5566 This->palettes = palettes;
5567 This->NumberOfPalettes = NewSize;
5570 if (!This->palettes[PaletteNumber]) {
5571 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5572 if (!This->palettes[PaletteNumber]) {
5573 ERR("Out of memory!\n");
5574 return E_OUTOFMEMORY;
5578 for (j = 0; j < 256; ++j) {
5579 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5580 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5581 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5582 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5584 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5585 TRACE("(%p) : returning\n", This);
5589 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5592 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5593 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5594 /* What happens in such situation isn't documented; Native seems to silently abort
5595 on such conditions. Return Invalid Call. */
5596 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5597 return WINED3DERR_INVALIDCALL;
5599 for (j = 0; j < 256; ++j) {
5600 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5601 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5602 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5603 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5605 TRACE("(%p) : returning\n", This);
5609 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5611 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5612 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5613 (tested with reference rasterizer). Return Invalid Call. */
5614 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5615 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5616 return WINED3DERR_INVALIDCALL;
5618 /*TODO: stateblocks */
5619 if (This->currentPalette != PaletteNumber) {
5620 This->currentPalette = PaletteNumber;
5621 dirtify_p8_texture_samplers(This);
5623 TRACE("(%p) : returning\n", This);
5627 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 if (PaletteNumber == NULL) {
5630 WARN("(%p) : returning Invalid Call\n", This);
5631 return WINED3DERR_INVALIDCALL;
5633 /*TODO: stateblocks */
5634 *PaletteNumber = This->currentPalette;
5635 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5639 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5644 FIXME("(%p) : stub\n", This);
5648 This->softwareVertexProcessing = bSoftware;
5653 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5658 FIXME("(%p) : stub\n", This);
5661 return This->softwareVertexProcessing;
5665 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5667 IWineD3DSwapChain *swapChain;
5670 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5672 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5673 if(hr == WINED3D_OK){
5674 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5675 IWineD3DSwapChain_Release(swapChain);
5677 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5683 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 if(nSegments != 0.0f) {
5689 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5696 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5701 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5707 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5709 /** TODO: remove casts to IWineD3DSurfaceImpl
5710 * NOTE: move code to surface to accomplish this
5711 ****************************************/
5712 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5713 int srcWidth, srcHeight;
5714 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5715 WINED3DFORMAT destFormat, srcFormat;
5717 int srcLeft, destLeft, destTop;
5718 WINED3DPOOL srcPool, destPool;
5720 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5721 glDescriptor *glDescription = NULL;
5725 CONVERT_TYPES convert = NO_CONVERSION;
5727 WINED3DSURFACE_DESC winedesc;
5729 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5730 memset(&winedesc, 0, sizeof(winedesc));
5731 winedesc.Width = &srcSurfaceWidth;
5732 winedesc.Height = &srcSurfaceHeight;
5733 winedesc.Pool = &srcPool;
5734 winedesc.Format = &srcFormat;
5736 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5738 winedesc.Width = &destSurfaceWidth;
5739 winedesc.Height = &destSurfaceHeight;
5740 winedesc.Pool = &destPool;
5741 winedesc.Format = &destFormat;
5742 winedesc.Size = &destSize;
5744 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5746 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5747 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5748 return WINED3DERR_INVALIDCALL;
5751 /* This call loads the opengl surface directly, instead of copying the surface to the
5752 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5753 * copy in sysmem and use regular surface loading.
5755 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5756 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5757 if(convert != NO_CONVERSION) {
5758 return IWineD3DSurface_BltFast(pDestinationSurface,
5759 pDestPoint ? pDestPoint->x : 0,
5760 pDestPoint ? pDestPoint->y : 0,
5761 pSourceSurface, pSourceRect, 0);
5764 if (destFormat == WINED3DFMT_UNKNOWN) {
5765 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5766 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5768 /* Get the update surface description */
5769 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5772 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5775 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5776 checkGLcall("glActiveTextureARB");
5779 /* Make sure the surface is loaded and up to date */
5780 IWineD3DSurface_PreLoad(pDestinationSurface);
5781 IWineD3DSurface_BindTexture(pDestinationSurface);
5783 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5785 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5786 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5787 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5788 srcLeft = pSourceRect ? pSourceRect->left : 0;
5789 destLeft = pDestPoint ? pDestPoint->x : 0;
5790 destTop = pDestPoint ? pDestPoint->y : 0;
5793 /* This function doesn't support compressed textures
5794 the pitch is just bytesPerPixel * width */
5795 if(srcWidth != srcSurfaceWidth || srcLeft ){
5796 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5797 offset += srcLeft * pSrcSurface->bytesPerPixel;
5798 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5800 /* TODO DXT formats */
5802 if(pSourceRect != NULL && pSourceRect->top != 0){
5803 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5805 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5806 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5807 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5810 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5812 /* need to lock the surface to get the data */
5813 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5818 /* TODO: Cube and volume support */
5820 /* not a whole row so we have to do it a line at a time */
5823 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5824 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5826 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5828 glTexSubImage2D(glDescription->target
5829 ,glDescription->level
5834 ,glDescription->glFormat
5835 ,glDescription->glType
5836 ,data /* could be quicker using */
5841 } else { /* Full width, so just write out the whole texture */
5842 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5844 if (WINED3DFMT_DXT1 == destFormat ||
5845 WINED3DFMT_DXT2 == destFormat ||
5846 WINED3DFMT_DXT3 == destFormat ||
5847 WINED3DFMT_DXT4 == destFormat ||
5848 WINED3DFMT_DXT5 == destFormat) {
5849 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5850 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5851 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5852 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5853 } if (destFormat != srcFormat) {
5854 FIXME("Updating mixed format compressed texture is not curretly support\n");
5856 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5857 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5860 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5865 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5866 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5869 checkGLcall("glTexSubImage2D");
5873 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5874 sampler = This->rev_tex_unit_map[0];
5875 if (sampler != -1) {
5876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5882 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5884 struct WineD3DRectPatch *patch;
5888 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5890 if(!(Handle || pRectPatchInfo)) {
5891 /* TODO: Write a test for the return value, thus the FIXME */
5892 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5893 return WINED3DERR_INVALIDCALL;
5897 i = PATCHMAP_HASHFUNC(Handle);
5899 LIST_FOR_EACH(e, &This->patches[i]) {
5900 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5901 if(patch->Handle == Handle) {
5908 TRACE("Patch does not exist. Creating a new one\n");
5909 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5910 patch->Handle = Handle;
5911 list_add_head(&This->patches[i], &patch->entry);
5913 TRACE("Found existing patch %p\n", patch);
5916 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5917 * attributes we have to tesselate, read back, and draw. This needs a patch
5918 * management structure instance. Create one.
5920 * A possible improvement is to check if a vertex shader is used, and if not directly
5923 FIXME("Drawing an uncached patch. This is slow\n");
5924 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5927 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5928 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5929 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5931 TRACE("Tesselation density or patch info changed, retesselating\n");
5933 if(pRectPatchInfo) {
5934 patch->RectPatchInfo = *pRectPatchInfo;
5936 patch->numSegs[0] = pNumSegs[0];
5937 patch->numSegs[1] = pNumSegs[1];
5938 patch->numSegs[2] = pNumSegs[2];
5939 patch->numSegs[3] = pNumSegs[3];
5941 hr = tesselate_rectpatch(This, patch);
5943 WARN("Patch tesselation failed\n");
5945 /* Do not release the handle to store the params of the patch */
5947 HeapFree(GetProcessHeap(), 0, patch);
5953 This->currentPatch = patch;
5954 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5955 This->currentPatch = NULL;
5957 /* Destroy uncached patches */
5959 HeapFree(GetProcessHeap(), 0, patch->mem);
5960 HeapFree(GetProcessHeap(), 0, patch);
5965 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5967 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5968 FIXME("(%p) : Stub\n", This);
5972 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5975 struct WineD3DRectPatch *patch;
5977 TRACE("(%p) Handle(%d)\n", This, Handle);
5979 i = PATCHMAP_HASHFUNC(Handle);
5980 LIST_FOR_EACH(e, &This->patches[i]) {
5981 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5982 if(patch->Handle == Handle) {
5983 TRACE("Deleting patch %p\n", patch);
5984 list_remove(&patch->entry);
5985 HeapFree(GetProcessHeap(), 0, patch->mem);
5986 HeapFree(GetProcessHeap(), 0, patch);
5991 /* TODO: Write a test for the return value */
5992 FIXME("Attempt to destroy nonexistent patch\n");
5993 return WINED3DERR_INVALIDCALL;
5996 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5998 IWineD3DSwapChain *swapchain;
6000 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6001 if (SUCCEEDED(hr)) {
6002 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6009 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6011 IWineD3DSwapChain *swapchain;
6013 swapchain = get_swapchain(surface);
6017 TRACE("Surface %p is onscreen\n", surface);
6019 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6021 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6022 buffer = surface_get_gl_buffer(surface, swapchain);
6023 glDrawBuffer(buffer);
6024 checkGLcall("glDrawBuffer()");
6026 TRACE("Surface %p is offscreen\n", surface);
6028 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6030 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6031 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6032 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6033 checkGLcall("glFramebufferRenderbufferEXT");
6037 glEnable(GL_SCISSOR_TEST);
6039 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6041 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6042 rect->x2 - rect->x1, rect->y2 - rect->y1);
6044 checkGLcall("glScissor");
6045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6047 glDisable(GL_SCISSOR_TEST);
6049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6051 glDisable(GL_BLEND);
6052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6054 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6057 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6058 glClear(GL_COLOR_BUFFER_BIT);
6059 checkGLcall("glClear");
6061 if (This->activeContext->current_fbo) {
6062 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6064 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6065 checkGLcall("glBindFramebuffer()");
6068 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6069 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6070 glDrawBuffer(GL_BACK);
6071 checkGLcall("glDrawBuffer()");
6077 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6078 unsigned int r, g, b, a;
6081 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6082 destfmt == WINED3DFMT_R8G8B8)
6085 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6087 a = (color & 0xff000000) >> 24;
6088 r = (color & 0x00ff0000) >> 16;
6089 g = (color & 0x0000ff00) >> 8;
6090 b = (color & 0x000000ff) >> 0;
6094 case WINED3DFMT_R5G6B5:
6095 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6102 TRACE("Returning %08x\n", ret);
6105 case WINED3DFMT_X1R5G5B5:
6106 case WINED3DFMT_A1R5G5B5:
6115 TRACE("Returning %08x\n", ret);
6119 TRACE("Returning %08x\n", a);
6122 case WINED3DFMT_X4R4G4B4:
6123 case WINED3DFMT_A4R4G4B4:
6132 TRACE("Returning %08x\n", ret);
6135 case WINED3DFMT_R3G3B2:
6142 TRACE("Returning %08x\n", ret);
6145 case WINED3DFMT_X8B8G8R8:
6146 case WINED3DFMT_A8B8G8R8:
6151 TRACE("Returning %08x\n", ret);
6154 case WINED3DFMT_A2R10G10B10:
6156 r = (r * 1024) / 256;
6157 g = (g * 1024) / 256;
6158 b = (b * 1024) / 256;
6163 TRACE("Returning %08x\n", ret);
6166 case WINED3DFMT_A2B10G10R10:
6168 r = (r * 1024) / 256;
6169 g = (g * 1024) / 256;
6170 b = (b * 1024) / 256;
6175 TRACE("Returning %08x\n", ret);
6179 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6184 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6186 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6188 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6190 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6191 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6192 return WINED3DERR_INVALIDCALL;
6195 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6196 color_fill_fbo(iface, pSurface, pRect, color);
6199 /* Just forward this to the DirectDraw blitting engine */
6200 memset(&BltFx, 0, sizeof(BltFx));
6201 BltFx.dwSize = sizeof(BltFx);
6202 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6203 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6204 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6208 /* rendertarget and depth stencil functions */
6209 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6212 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6213 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6214 return WINED3DERR_INVALIDCALL;
6217 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6218 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6219 /* Note inc ref on returned surface */
6220 if(*ppRenderTarget != NULL)
6221 IWineD3DSurface_AddRef(*ppRenderTarget);
6225 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6227 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6228 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6229 IWineD3DSwapChainImpl *Swapchain;
6232 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6234 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6235 if(hr != WINED3D_OK) {
6236 ERR("Can't get the swapchain\n");
6240 /* Make sure to release the swapchain */
6241 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6243 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6244 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6245 return WINED3DERR_INVALIDCALL;
6247 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6248 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6249 return WINED3DERR_INVALIDCALL;
6252 if(Swapchain->frontBuffer != Front) {
6253 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6255 if(Swapchain->frontBuffer)
6256 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6257 Swapchain->frontBuffer = Front;
6259 if(Swapchain->frontBuffer) {
6260 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6264 if(Back && !Swapchain->backBuffer) {
6265 /* We need memory for the back buffer array - only one back buffer this way */
6266 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6267 if(!Swapchain->backBuffer) {
6268 ERR("Out of memory\n");
6269 return E_OUTOFMEMORY;
6273 if(Swapchain->backBuffer[0] != Back) {
6274 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6276 /* What to do about the context here in the case of multithreading? Not sure.
6277 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6280 if(!Swapchain->backBuffer[0]) {
6281 /* GL was told to draw to the front buffer at creation,
6284 glDrawBuffer(GL_BACK);
6285 checkGLcall("glDrawBuffer(GL_BACK)");
6286 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6287 Swapchain->presentParms.BackBufferCount = 1;
6289 /* That makes problems - disable for now */
6290 /* glDrawBuffer(GL_FRONT); */
6291 checkGLcall("glDrawBuffer(GL_FRONT)");
6292 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6293 Swapchain->presentParms.BackBufferCount = 0;
6297 if(Swapchain->backBuffer[0])
6298 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6299 Swapchain->backBuffer[0] = Back;
6301 if(Swapchain->backBuffer[0]) {
6302 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6304 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6305 Swapchain->backBuffer = NULL;
6313 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6315 *ppZStencilSurface = This->stencilBufferTarget;
6316 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6318 if(*ppZStencilSurface != NULL) {
6319 /* Note inc ref on returned surface */
6320 IWineD3DSurface_AddRef(*ppZStencilSurface);
6323 return WINED3DERR_NOTFOUND;
6327 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6328 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6331 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6332 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6334 POINT offset = {0, 0};
6336 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6337 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6338 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6339 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6342 case WINED3DTEXF_LINEAR:
6343 gl_filter = GL_LINEAR;
6347 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6348 case WINED3DTEXF_NONE:
6349 case WINED3DTEXF_POINT:
6350 gl_filter = GL_NEAREST;
6354 /* Attach src surface to src fbo */
6355 src_swapchain = get_swapchain(src_surface);
6356 if (src_swapchain) {
6357 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6359 TRACE("Source surface %p is onscreen\n", src_surface);
6360 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6361 /* Make sure the drawable is up to date. In the offscreen case
6362 * attach_surface_fbo() implicitly takes care of this. */
6363 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6365 if(buffer == GL_FRONT) {
6368 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6369 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6370 h = windowsize.bottom - windowsize.top;
6371 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6372 src_rect->y1 = offset.y + h - src_rect->y1;
6373 src_rect->y2 = offset.y + h - src_rect->y2;
6375 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6376 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6380 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6381 glReadBuffer(buffer);
6382 checkGLcall("glReadBuffer()");
6384 TRACE("Source surface %p is offscreen\n", src_surface);
6386 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6387 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6388 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6389 checkGLcall("glReadBuffer()");
6390 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6391 checkGLcall("glFramebufferRenderbufferEXT");
6395 /* Attach dst surface to dst fbo */
6396 dst_swapchain = get_swapchain(dst_surface);
6397 if (dst_swapchain) {
6398 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6400 TRACE("Destination surface %p is onscreen\n", dst_surface);
6401 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6402 /* Make sure the drawable is up to date. In the offscreen case
6403 * attach_surface_fbo() implicitly takes care of this. */
6404 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6406 if(buffer == GL_FRONT) {
6409 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6410 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6411 h = windowsize.bottom - windowsize.top;
6412 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6413 dst_rect->y1 = offset.y + h - dst_rect->y1;
6414 dst_rect->y2 = offset.y + h - dst_rect->y2;
6416 /* Screen coords = window coords, surface height = window height */
6417 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6418 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6422 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6423 glDrawBuffer(buffer);
6424 checkGLcall("glDrawBuffer()");
6426 TRACE("Destination surface %p is offscreen\n", dst_surface);
6428 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6429 if(!src_swapchain) {
6430 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6434 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6435 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6436 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6437 checkGLcall("glDrawBuffer()");
6438 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6439 checkGLcall("glFramebufferRenderbufferEXT");
6441 glDisable(GL_SCISSOR_TEST);
6442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6445 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6446 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6447 checkGLcall("glBlitFramebuffer()");
6449 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6450 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6451 checkGLcall("glBlitFramebuffer()");
6454 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6456 if (This->activeContext->current_fbo) {
6457 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6459 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6460 checkGLcall("glBindFramebuffer()");
6463 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6464 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6465 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6466 glDrawBuffer(GL_BACK);
6467 checkGLcall("glDrawBuffer()");
6472 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6474 WINED3DVIEWPORT viewport;
6476 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6478 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6479 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6480 This, RenderTargetIndex, GL_LIMITS(buffers));
6481 return WINED3DERR_INVALIDCALL;
6484 /* MSDN says that null disables the render target
6485 but a device must always be associated with a render target
6486 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6488 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6489 FIXME("Trying to set render target 0 to NULL\n");
6490 return WINED3DERR_INVALIDCALL;
6492 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6493 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);
6494 return WINED3DERR_INVALIDCALL;
6497 /* If we are trying to set what we already have, don't bother */
6498 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6499 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6502 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6503 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6504 This->render_targets[RenderTargetIndex] = pRenderTarget;
6506 /* Render target 0 is special */
6507 if(RenderTargetIndex == 0) {
6508 /* Finally, reset the viewport as the MSDN states. */
6509 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6510 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6513 viewport.MaxZ = 1.0f;
6514 viewport.MinZ = 0.0f;
6515 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6516 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6517 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6524 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6526 HRESULT hr = WINED3D_OK;
6527 IWineD3DSurface *tmp;
6529 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6531 if (pNewZStencil == This->stencilBufferTarget) {
6532 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6534 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6535 * depending on the renter target implementation being used.
6536 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6537 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6538 * stencil buffer and incur an extra memory overhead
6539 ******************************************************/
6541 if (This->stencilBufferTarget) {
6542 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6543 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6544 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6546 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6547 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6548 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6552 tmp = This->stencilBufferTarget;
6553 This->stencilBufferTarget = pNewZStencil;
6554 /* should we be calling the parent or the wined3d surface? */
6555 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6556 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6559 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6560 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6570 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6571 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6573 /* TODO: the use of Impl is deprecated. */
6574 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6575 WINED3DLOCKED_RECT lockedRect;
6577 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6579 /* some basic validation checks */
6580 if(This->cursorTexture) {
6581 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6583 glDeleteTextures(1, &This->cursorTexture);
6585 This->cursorTexture = 0;
6588 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6589 This->haveHardwareCursor = TRUE;
6591 This->haveHardwareCursor = FALSE;
6594 WINED3DLOCKED_RECT rect;
6596 /* MSDN: Cursor must be A8R8G8B8 */
6597 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6598 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6599 return WINED3DERR_INVALIDCALL;
6602 /* MSDN: Cursor must be smaller than the display mode */
6603 if(pSur->currentDesc.Width > This->ddraw_width ||
6604 pSur->currentDesc.Height > This->ddraw_height) {
6605 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);
6606 return WINED3DERR_INVALIDCALL;
6609 if (!This->haveHardwareCursor) {
6610 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6612 /* Do not store the surface's pointer because the application may
6613 * release it after setting the cursor image. Windows doesn't
6614 * addref the set surface, so we can't do this either without
6615 * creating circular refcount dependencies. Copy out the gl texture
6618 This->cursorWidth = pSur->currentDesc.Width;
6619 This->cursorHeight = pSur->currentDesc.Height;
6620 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6622 const struct GlPixelFormatDesc *glDesc;
6623 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6624 char *mem, *bits = (char *)rect.pBits;
6625 GLint intfmt = glDesc->glInternal;
6626 GLint format = glDesc->glFormat;
6627 GLint type = glDesc->glType;
6628 INT height = This->cursorHeight;
6629 INT width = This->cursorWidth;
6630 INT bpp = tableEntry->bpp;
6633 /* Reformat the texture memory (pitch and width can be
6635 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6636 for(i = 0; i < height; i++)
6637 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6638 IWineD3DSurface_UnlockRect(pCursorBitmap);
6641 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6642 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6643 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6646 /* Make sure that a proper texture unit is selected */
6647 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6648 checkGLcall("glActiveTextureARB");
6649 sampler = This->rev_tex_unit_map[0];
6650 if (sampler != -1) {
6651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6653 /* Create a new cursor texture */
6654 glGenTextures(1, &This->cursorTexture);
6655 checkGLcall("glGenTextures");
6656 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6657 checkGLcall("glBindTexture");
6658 /* Copy the bitmap memory into the cursor texture */
6659 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6660 HeapFree(GetProcessHeap(), 0, mem);
6661 checkGLcall("glTexImage2D");
6663 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6664 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6665 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6672 FIXME("A cursor texture was not returned.\n");
6673 This->cursorTexture = 0;
6678 /* Draw a hardware cursor */
6679 ICONINFO cursorInfo;
6681 /* Create and clear maskBits because it is not needed for
6682 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6684 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6685 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6686 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6687 WINED3DLOCK_NO_DIRTY_UPDATE |
6688 WINED3DLOCK_READONLY
6690 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6691 pSur->currentDesc.Height);
6693 cursorInfo.fIcon = FALSE;
6694 cursorInfo.xHotspot = XHotSpot;
6695 cursorInfo.yHotspot = YHotSpot;
6696 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6697 pSur->currentDesc.Height, 1,
6699 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6700 pSur->currentDesc.Height, 1,
6701 32, lockedRect.pBits);
6702 IWineD3DSurface_UnlockRect(pCursorBitmap);
6703 /* Create our cursor and clean up. */
6704 cursor = CreateIconIndirect(&cursorInfo);
6706 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6707 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6708 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6709 This->hardwareCursor = cursor;
6710 HeapFree(GetProcessHeap(), 0, maskBits);
6714 This->xHotSpot = XHotSpot;
6715 This->yHotSpot = YHotSpot;
6719 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6721 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6723 This->xScreenSpace = XScreenSpace;
6724 This->yScreenSpace = YScreenSpace;
6730 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6732 BOOL oldVisible = This->bCursorVisible;
6735 TRACE("(%p) : visible(%d)\n", This, bShow);
6738 * When ShowCursor is first called it should make the cursor appear at the OS's last
6739 * known cursor position. Because of this, some applications just repetitively call
6740 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6743 This->xScreenSpace = pt.x;
6744 This->yScreenSpace = pt.y;
6746 if (This->haveHardwareCursor) {
6747 This->bCursorVisible = bShow;
6749 SetCursor(This->hardwareCursor);
6755 if (This->cursorTexture)
6756 This->bCursorVisible = bShow;
6762 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6764 IWineD3DResourceImpl *resource;
6765 TRACE("(%p) : state (%u)\n", This, This->state);
6767 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6768 switch (This->state) {
6771 case WINED3DERR_DEVICELOST:
6773 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6774 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6775 return WINED3DERR_DEVICENOTRESET;
6777 return WINED3DERR_DEVICELOST;
6779 case WINED3DERR_DRIVERINTERNALERROR:
6780 return WINED3DERR_DRIVERINTERNALERROR;
6784 return WINED3DERR_DRIVERINTERNALERROR;
6788 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6790 /** FIXME: Resource tracking needs to be done,
6791 * The closes we can do to this is set the priorities of all managed textures low
6792 * and then reset them.
6793 ***********************************************************/
6794 FIXME("(%p) : stub\n", This);
6798 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6800 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6802 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6803 if(surface->Flags & SFLAG_DIBSECTION) {
6804 /* Release the DC */
6805 SelectObject(surface->hDC, surface->dib.holdbitmap);
6806 DeleteDC(surface->hDC);
6807 /* Release the DIB section */
6808 DeleteObject(surface->dib.DIBsection);
6809 surface->dib.bitmap_data = NULL;
6810 surface->resource.allocatedMemory = NULL;
6811 surface->Flags &= ~SFLAG_DIBSECTION;
6813 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6814 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6815 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6816 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6817 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6818 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6820 surface->pow2Width = surface->pow2Height = 1;
6821 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6822 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6824 surface->glRect.left = 0;
6825 surface->glRect.top = 0;
6826 surface->glRect.right = surface->pow2Width;
6827 surface->glRect.bottom = surface->pow2Height;
6829 if(surface->glDescription.textureName) {
6830 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6832 glDeleteTextures(1, &surface->glDescription.textureName);
6834 surface->glDescription.textureName = 0;
6835 surface->Flags &= ~SFLAG_CLIENT;
6837 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6838 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6839 surface->Flags |= SFLAG_NONPOW2;
6841 surface->Flags &= ~SFLAG_NONPOW2;
6843 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6844 surface->resource.allocatedMemory = NULL;
6845 surface->resource.heapMemory = NULL;
6846 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6847 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6848 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6849 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6851 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6855 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6856 TRACE("Unloading resource %p\n", resource);
6857 IWineD3DResource_UnLoad(resource);
6858 IWineD3DResource_Release(resource);
6862 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6865 WINED3DDISPLAYMODE m;
6868 /* All Windowed modes are supported, as is leaving the current mode */
6869 if(pp->Windowed) return TRUE;
6870 if(!pp->BackBufferWidth) return TRUE;
6871 if(!pp->BackBufferHeight) return TRUE;
6873 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6874 for(i = 0; i < count; i++) {
6875 memset(&m, 0, sizeof(m));
6876 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6878 ERR("EnumAdapterModes failed\n");
6880 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6881 /* Mode found, it is supported */
6885 /* Mode not found -> not supported */
6889 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6891 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6893 IWineD3DBaseShaderImpl *shader;
6895 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6896 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6897 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6901 if(This->depth_blt_texture) {
6902 glDeleteTextures(1, &This->depth_blt_texture);
6903 This->depth_blt_texture = 0;
6905 if (This->depth_blt_rb) {
6906 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6907 This->depth_blt_rb = 0;
6908 This->depth_blt_rb_w = 0;
6909 This->depth_blt_rb_h = 0;
6913 This->blitter->free_private(iface);
6914 This->frag_pipe->free_private(iface);
6915 This->shader_backend->shader_free_private(iface);
6918 for (i = 0; i < GL_LIMITS(textures); i++) {
6919 /* Textures are recreated below */
6920 glDeleteTextures(1, &This->dummyTextureName[i]);
6921 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6922 This->dummyTextureName[i] = 0;
6926 while(This->numContexts) {
6927 DestroyContext(This, This->contexts[0]);
6929 This->activeContext = NULL;
6930 HeapFree(GetProcessHeap(), 0, swapchain->context);
6931 swapchain->context = NULL;
6932 swapchain->num_contexts = 0;
6935 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6937 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6939 IWineD3DSurfaceImpl *target;
6941 /* Recreate the primary swapchain's context */
6942 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6943 if(swapchain->backBuffer) {
6944 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6946 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6948 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6949 &swapchain->presentParms);
6950 swapchain->num_contexts = 1;
6951 This->activeContext = swapchain->context[0];
6953 create_dummy_textures(This);
6955 hr = This->shader_backend->shader_alloc_private(iface);
6957 ERR("Failed to recreate shader private data\n");
6960 hr = This->frag_pipe->alloc_private(iface);
6962 TRACE("Fragment pipeline private data couldn't be allocated\n");
6965 hr = This->blitter->alloc_private(iface);
6967 TRACE("Blitter private data couldn't be allocated\n");
6974 This->blitter->free_private(iface);
6975 This->frag_pipe->free_private(iface);
6976 This->shader_backend->shader_free_private(iface);
6980 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6982 IWineD3DSwapChainImpl *swapchain;
6984 BOOL DisplayModeChanged = FALSE;
6985 WINED3DDISPLAYMODE mode;
6986 TRACE("(%p)\n", This);
6988 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6990 ERR("Failed to get the first implicit swapchain\n");
6994 if(!is_display_mode_supported(This, pPresentationParameters)) {
6995 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6996 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6997 pPresentationParameters->BackBufferHeight);
6998 return WINED3DERR_INVALIDCALL;
7001 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7002 * on an existing gl context, so there's no real need for recreation.
7004 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7006 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7008 TRACE("New params:\n");
7009 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7010 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7011 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7012 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7013 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7014 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7015 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7016 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7017 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7018 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7019 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7020 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7021 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7023 /* No special treatment of these parameters. Just store them */
7024 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7025 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7026 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7027 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7029 /* What to do about these? */
7030 if(pPresentationParameters->BackBufferCount != 0 &&
7031 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7032 ERR("Cannot change the back buffer count yet\n");
7034 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7035 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7036 ERR("Cannot change the back buffer format yet\n");
7038 if(pPresentationParameters->hDeviceWindow != NULL &&
7039 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7040 ERR("Cannot change the device window yet\n");
7042 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7043 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7044 return WINED3DERR_INVALIDCALL;
7047 /* Reset the depth stencil */
7048 if (pPresentationParameters->EnableAutoDepthStencil)
7049 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7051 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7053 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7055 if(pPresentationParameters->Windowed) {
7056 mode.Width = swapchain->orig_width;
7057 mode.Height = swapchain->orig_height;
7058 mode.RefreshRate = 0;
7059 mode.Format = swapchain->presentParms.BackBufferFormat;
7061 mode.Width = pPresentationParameters->BackBufferWidth;
7062 mode.Height = pPresentationParameters->BackBufferHeight;
7063 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7064 mode.Format = swapchain->presentParms.BackBufferFormat;
7067 /* Should Width == 800 && Height == 0 set 800x600? */
7068 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7069 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7070 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7074 if(!pPresentationParameters->Windowed) {
7075 DisplayModeChanged = TRUE;
7077 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7078 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7080 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7081 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7082 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7084 if(This->auto_depth_stencil_buffer) {
7085 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7089 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7090 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7091 DisplayModeChanged) {
7093 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7095 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7096 if(swapchain->presentParms.Windowed) {
7097 /* switch from windowed to fs */
7098 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7099 pPresentationParameters->BackBufferWidth,
7100 pPresentationParameters->BackBufferHeight);
7102 /* Fullscreen -> fullscreen mode change */
7103 MoveWindow(swapchain->win_handle, 0, 0,
7104 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7107 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7108 /* Fullscreen -> windowed switch */
7109 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7111 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7112 } else if(!pPresentationParameters->Windowed) {
7113 DWORD style = This->style, exStyle = This->exStyle;
7114 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7115 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7116 * Reset to clear up their mess. Guild Wars also loses the device during that.
7120 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7121 pPresentationParameters->BackBufferWidth,
7122 pPresentationParameters->BackBufferHeight);
7123 This->style = style;
7124 This->exStyle = exStyle;
7127 TRACE("Resetting stateblock\n");
7128 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7129 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7131 /* Note: No parent needed for initial internal stateblock */
7132 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7133 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7134 else TRACE("Created stateblock %p\n", This->stateBlock);
7135 This->updateStateBlock = This->stateBlock;
7136 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7138 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7140 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7143 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7144 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7146 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7152 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7154 /** FIXME: always true at the moment **/
7155 if(!bEnableDialogs) {
7156 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7162 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7164 TRACE("(%p) : pParameters %p\n", This, pParameters);
7166 *pParameters = This->createParms;
7170 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7171 IWineD3DSwapChain *swapchain;
7173 TRACE("Relaying to swapchain\n");
7175 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7176 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7177 IWineD3DSwapChain_Release(swapchain);
7182 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7183 IWineD3DSwapChain *swapchain;
7185 TRACE("Relaying to swapchain\n");
7187 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7188 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7189 IWineD3DSwapChain_Release(swapchain);
7195 /** ********************************************************
7196 * Notification functions
7197 ** ********************************************************/
7198 /** This function must be called in the release of a resource when ref == 0,
7199 * the contents of resource must still be correct,
7200 * any handles to other resource held by the caller must be closed
7201 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7202 *****************************************************/
7203 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7206 TRACE("(%p) : Adding Resource %p\n", This, resource);
7207 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7210 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7213 TRACE("(%p) : Removing resource %p\n", This, resource);
7215 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7219 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7221 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7224 TRACE("(%p) : resource %p\n", This, resource);
7226 context_resource_released(iface, resource, type);
7229 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7230 case WINED3DRTYPE_SURFACE: {
7233 /* Cleanup any FBO attachments if d3d is enabled */
7234 if(This->d3d_initialized) {
7235 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7236 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7238 TRACE("Last active render target destroyed\n");
7239 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7240 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7241 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7242 * and the lastActiveRenderTarget member shouldn't matter
7245 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7246 TRACE("Activating primary back buffer\n");
7247 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7248 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7249 /* Single buffering environment */
7250 TRACE("Activating primary front buffer\n");
7251 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7253 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7254 /* Implicit render target destroyed, that means the device is being destroyed
7255 * whatever we set here, it shouldn't matter
7257 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7260 /* May happen during ddraw uninitialization */
7261 TRACE("Render target set, but swapchain does not exist!\n");
7262 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7266 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7267 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7268 This->render_targets[i] = NULL;
7271 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7272 This->stencilBufferTarget = NULL;
7278 case WINED3DRTYPE_TEXTURE:
7279 case WINED3DRTYPE_CUBETEXTURE:
7280 case WINED3DRTYPE_VOLUMETEXTURE:
7281 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7282 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7283 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7284 This->stateBlock->textures[counter] = NULL;
7286 if (This->updateStateBlock != This->stateBlock ){
7287 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7288 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7289 This->updateStateBlock->textures[counter] = NULL;
7294 case WINED3DRTYPE_VOLUME:
7295 /* TODO: nothing really? */
7297 case WINED3DRTYPE_VERTEXBUFFER:
7298 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7301 TRACE("Cleaning up stream pointers\n");
7303 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7304 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7305 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7307 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7308 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7309 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7310 This->updateStateBlock->streamSource[streamNumber] = 0;
7311 /* Set changed flag? */
7314 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) */
7315 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7316 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7317 This->stateBlock->streamSource[streamNumber] = 0;
7323 case WINED3DRTYPE_INDEXBUFFER:
7324 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7325 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7326 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7327 This->updateStateBlock->pIndexData = NULL;
7330 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7331 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7332 This->stateBlock->pIndexData = NULL;
7338 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7343 /* Remove the resource from the resourceStore */
7344 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7346 TRACE("Resource released\n");
7350 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7352 IWineD3DResourceImpl *resource, *cursor;
7354 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7356 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7357 TRACE("enumerating resource %p\n", resource);
7358 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7359 ret = pCallback((IWineD3DResource *) resource, pData);
7360 if(ret == S_FALSE) {
7361 TRACE("Canceling enumeration\n");
7368 /**********************************************************
7369 * IWineD3DDevice VTbl follows
7370 **********************************************************/
7372 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7374 /*** IUnknown methods ***/
7375 IWineD3DDeviceImpl_QueryInterface,
7376 IWineD3DDeviceImpl_AddRef,
7377 IWineD3DDeviceImpl_Release,
7378 /*** IWineD3DDevice methods ***/
7379 IWineD3DDeviceImpl_GetParent,
7380 /*** Creation methods**/
7381 IWineD3DDeviceImpl_CreateVertexBuffer,
7382 IWineD3DDeviceImpl_CreateIndexBuffer,
7383 IWineD3DDeviceImpl_CreateStateBlock,
7384 IWineD3DDeviceImpl_CreateSurface,
7385 IWineD3DDeviceImpl_CreateTexture,
7386 IWineD3DDeviceImpl_CreateVolumeTexture,
7387 IWineD3DDeviceImpl_CreateVolume,
7388 IWineD3DDeviceImpl_CreateCubeTexture,
7389 IWineD3DDeviceImpl_CreateQuery,
7390 IWineD3DDeviceImpl_CreateSwapChain,
7391 IWineD3DDeviceImpl_CreateVertexDeclaration,
7392 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7393 IWineD3DDeviceImpl_CreateVertexShader,
7394 IWineD3DDeviceImpl_CreatePixelShader,
7395 IWineD3DDeviceImpl_CreatePalette,
7396 /*** Odd functions **/
7397 IWineD3DDeviceImpl_Init3D,
7398 IWineD3DDeviceImpl_InitGDI,
7399 IWineD3DDeviceImpl_Uninit3D,
7400 IWineD3DDeviceImpl_UninitGDI,
7401 IWineD3DDeviceImpl_SetMultithreaded,
7402 IWineD3DDeviceImpl_EvictManagedResources,
7403 IWineD3DDeviceImpl_GetAvailableTextureMem,
7404 IWineD3DDeviceImpl_GetBackBuffer,
7405 IWineD3DDeviceImpl_GetCreationParameters,
7406 IWineD3DDeviceImpl_GetDeviceCaps,
7407 IWineD3DDeviceImpl_GetDirect3D,
7408 IWineD3DDeviceImpl_GetDisplayMode,
7409 IWineD3DDeviceImpl_SetDisplayMode,
7410 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7411 IWineD3DDeviceImpl_GetRasterStatus,
7412 IWineD3DDeviceImpl_GetSwapChain,
7413 IWineD3DDeviceImpl_Reset,
7414 IWineD3DDeviceImpl_SetDialogBoxMode,
7415 IWineD3DDeviceImpl_SetCursorProperties,
7416 IWineD3DDeviceImpl_SetCursorPosition,
7417 IWineD3DDeviceImpl_ShowCursor,
7418 IWineD3DDeviceImpl_TestCooperativeLevel,
7419 /*** Getters and setters **/
7420 IWineD3DDeviceImpl_SetClipPlane,
7421 IWineD3DDeviceImpl_GetClipPlane,
7422 IWineD3DDeviceImpl_SetClipStatus,
7423 IWineD3DDeviceImpl_GetClipStatus,
7424 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7425 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7426 IWineD3DDeviceImpl_SetDepthStencilSurface,
7427 IWineD3DDeviceImpl_GetDepthStencilSurface,
7428 IWineD3DDeviceImpl_SetGammaRamp,
7429 IWineD3DDeviceImpl_GetGammaRamp,
7430 IWineD3DDeviceImpl_SetIndices,
7431 IWineD3DDeviceImpl_GetIndices,
7432 IWineD3DDeviceImpl_SetBaseVertexIndex,
7433 IWineD3DDeviceImpl_GetBaseVertexIndex,
7434 IWineD3DDeviceImpl_SetLight,
7435 IWineD3DDeviceImpl_GetLight,
7436 IWineD3DDeviceImpl_SetLightEnable,
7437 IWineD3DDeviceImpl_GetLightEnable,
7438 IWineD3DDeviceImpl_SetMaterial,
7439 IWineD3DDeviceImpl_GetMaterial,
7440 IWineD3DDeviceImpl_SetNPatchMode,
7441 IWineD3DDeviceImpl_GetNPatchMode,
7442 IWineD3DDeviceImpl_SetPaletteEntries,
7443 IWineD3DDeviceImpl_GetPaletteEntries,
7444 IWineD3DDeviceImpl_SetPixelShader,
7445 IWineD3DDeviceImpl_GetPixelShader,
7446 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7447 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7448 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7449 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7450 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7451 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7452 IWineD3DDeviceImpl_SetRenderState,
7453 IWineD3DDeviceImpl_GetRenderState,
7454 IWineD3DDeviceImpl_SetRenderTarget,
7455 IWineD3DDeviceImpl_GetRenderTarget,
7456 IWineD3DDeviceImpl_SetFrontBackBuffers,
7457 IWineD3DDeviceImpl_SetSamplerState,
7458 IWineD3DDeviceImpl_GetSamplerState,
7459 IWineD3DDeviceImpl_SetScissorRect,
7460 IWineD3DDeviceImpl_GetScissorRect,
7461 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7462 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7463 IWineD3DDeviceImpl_SetStreamSource,
7464 IWineD3DDeviceImpl_GetStreamSource,
7465 IWineD3DDeviceImpl_SetStreamSourceFreq,
7466 IWineD3DDeviceImpl_GetStreamSourceFreq,
7467 IWineD3DDeviceImpl_SetTexture,
7468 IWineD3DDeviceImpl_GetTexture,
7469 IWineD3DDeviceImpl_SetTextureStageState,
7470 IWineD3DDeviceImpl_GetTextureStageState,
7471 IWineD3DDeviceImpl_SetTransform,
7472 IWineD3DDeviceImpl_GetTransform,
7473 IWineD3DDeviceImpl_SetVertexDeclaration,
7474 IWineD3DDeviceImpl_GetVertexDeclaration,
7475 IWineD3DDeviceImpl_SetVertexShader,
7476 IWineD3DDeviceImpl_GetVertexShader,
7477 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7478 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7479 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7480 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7481 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7482 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7483 IWineD3DDeviceImpl_SetViewport,
7484 IWineD3DDeviceImpl_GetViewport,
7485 IWineD3DDeviceImpl_MultiplyTransform,
7486 IWineD3DDeviceImpl_ValidateDevice,
7487 IWineD3DDeviceImpl_ProcessVertices,
7488 /*** State block ***/
7489 IWineD3DDeviceImpl_BeginStateBlock,
7490 IWineD3DDeviceImpl_EndStateBlock,
7491 /*** Scene management ***/
7492 IWineD3DDeviceImpl_BeginScene,
7493 IWineD3DDeviceImpl_EndScene,
7494 IWineD3DDeviceImpl_Present,
7495 IWineD3DDeviceImpl_Clear,
7497 IWineD3DDeviceImpl_DrawPrimitive,
7498 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7499 IWineD3DDeviceImpl_DrawPrimitiveUP,
7500 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7501 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7502 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7503 IWineD3DDeviceImpl_DrawRectPatch,
7504 IWineD3DDeviceImpl_DrawTriPatch,
7505 IWineD3DDeviceImpl_DeletePatch,
7506 IWineD3DDeviceImpl_ColorFill,
7507 IWineD3DDeviceImpl_UpdateTexture,
7508 IWineD3DDeviceImpl_UpdateSurface,
7509 IWineD3DDeviceImpl_GetFrontBufferData,
7510 /*** object tracking ***/
7511 IWineD3DDeviceImpl_ResourceReleased,
7512 IWineD3DDeviceImpl_EnumResources
7515 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7516 WINED3DRS_ALPHABLENDENABLE ,
7517 WINED3DRS_ALPHAFUNC ,
7518 WINED3DRS_ALPHAREF ,
7519 WINED3DRS_ALPHATESTENABLE ,
7521 WINED3DRS_COLORWRITEENABLE ,
7522 WINED3DRS_DESTBLEND ,
7523 WINED3DRS_DITHERENABLE ,
7524 WINED3DRS_FILLMODE ,
7525 WINED3DRS_FOGDENSITY ,
7527 WINED3DRS_FOGSTART ,
7528 WINED3DRS_LASTPIXEL ,
7529 WINED3DRS_SHADEMODE ,
7530 WINED3DRS_SRCBLEND ,
7531 WINED3DRS_STENCILENABLE ,
7532 WINED3DRS_STENCILFAIL ,
7533 WINED3DRS_STENCILFUNC ,
7534 WINED3DRS_STENCILMASK ,
7535 WINED3DRS_STENCILPASS ,
7536 WINED3DRS_STENCILREF ,
7537 WINED3DRS_STENCILWRITEMASK ,
7538 WINED3DRS_STENCILZFAIL ,
7539 WINED3DRS_TEXTUREFACTOR ,
7550 WINED3DRS_ZWRITEENABLE
7553 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7554 WINED3DTSS_ADDRESSW ,
7555 WINED3DTSS_ALPHAARG0 ,
7556 WINED3DTSS_ALPHAARG1 ,
7557 WINED3DTSS_ALPHAARG2 ,
7558 WINED3DTSS_ALPHAOP ,
7559 WINED3DTSS_BUMPENVLOFFSET ,
7560 WINED3DTSS_BUMPENVLSCALE ,
7561 WINED3DTSS_BUMPENVMAT00 ,
7562 WINED3DTSS_BUMPENVMAT01 ,
7563 WINED3DTSS_BUMPENVMAT10 ,
7564 WINED3DTSS_BUMPENVMAT11 ,
7565 WINED3DTSS_COLORARG0 ,
7566 WINED3DTSS_COLORARG1 ,
7567 WINED3DTSS_COLORARG2 ,
7568 WINED3DTSS_COLOROP ,
7569 WINED3DTSS_RESULTARG ,
7570 WINED3DTSS_TEXCOORDINDEX ,
7571 WINED3DTSS_TEXTURETRANSFORMFLAGS
7574 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7575 WINED3DSAMP_ADDRESSU ,
7576 WINED3DSAMP_ADDRESSV ,
7577 WINED3DSAMP_ADDRESSW ,
7578 WINED3DSAMP_BORDERCOLOR ,
7579 WINED3DSAMP_MAGFILTER ,
7580 WINED3DSAMP_MINFILTER ,
7581 WINED3DSAMP_MIPFILTER ,
7582 WINED3DSAMP_MIPMAPLODBIAS ,
7583 WINED3DSAMP_MAXMIPLEVEL ,
7584 WINED3DSAMP_MAXANISOTROPY ,
7585 WINED3DSAMP_SRGBTEXTURE ,
7586 WINED3DSAMP_ELEMENTINDEX
7589 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7591 WINED3DRS_AMBIENTMATERIALSOURCE ,
7592 WINED3DRS_CLIPPING ,
7593 WINED3DRS_CLIPPLANEENABLE ,
7594 WINED3DRS_COLORVERTEX ,
7595 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7596 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7597 WINED3DRS_FOGDENSITY ,
7599 WINED3DRS_FOGSTART ,
7600 WINED3DRS_FOGTABLEMODE ,
7601 WINED3DRS_FOGVERTEXMODE ,
7602 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7603 WINED3DRS_LIGHTING ,
7604 WINED3DRS_LOCALVIEWER ,
7605 WINED3DRS_MULTISAMPLEANTIALIAS ,
7606 WINED3DRS_MULTISAMPLEMASK ,
7607 WINED3DRS_NORMALIZENORMALS ,
7608 WINED3DRS_PATCHEDGESTYLE ,
7609 WINED3DRS_POINTSCALE_A ,
7610 WINED3DRS_POINTSCALE_B ,
7611 WINED3DRS_POINTSCALE_C ,
7612 WINED3DRS_POINTSCALEENABLE ,
7613 WINED3DRS_POINTSIZE ,
7614 WINED3DRS_POINTSIZE_MAX ,
7615 WINED3DRS_POINTSIZE_MIN ,
7616 WINED3DRS_POINTSPRITEENABLE ,
7617 WINED3DRS_RANGEFOGENABLE ,
7618 WINED3DRS_SPECULARMATERIALSOURCE ,
7619 WINED3DRS_TWEENFACTOR ,
7620 WINED3DRS_VERTEXBLEND ,
7621 WINED3DRS_CULLMODE ,
7625 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7626 WINED3DTSS_TEXCOORDINDEX ,
7627 WINED3DTSS_TEXTURETRANSFORMFLAGS
7630 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7631 WINED3DSAMP_DMAPOFFSET
7634 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7635 DWORD rep = This->StateTable[state].representative;
7639 WineD3DContext *context;
7642 for(i = 0; i < This->numContexts; i++) {
7643 context = This->contexts[i];
7644 if(isStateDirty(context, rep)) continue;
7646 context->dirtyArray[context->numDirtyEntries++] = rep;
7649 context->isStateDirty[idx] |= (1 << shift);
7653 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7654 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7655 /* The drawable size of a pbuffer render target is the current pbuffer size
7657 *width = dev->pbufferWidth;
7658 *height = dev->pbufferHeight;
7661 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7662 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7664 *width = This->pow2Width;
7665 *height = This->pow2Height;
7668 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7669 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7670 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7671 * current context's drawable, which is the size of the back buffer of the swapchain
7672 * the active context belongs to. The back buffer of the swapchain is stored as the
7673 * surface the context belongs to.
7675 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7676 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;