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-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
139 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
140 if (IsEqualGUID(riid
, &IID_IUnknown
)
141 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
142 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
143 IUnknown_AddRef(iface
);
148 return E_NOINTERFACE
;
151 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
152 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
153 ULONG refCount
= InterlockedIncrement(&This
->ref
);
155 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
159 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
161 ULONG refCount
= InterlockedDecrement(&This
->ref
);
163 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->src_fbo
));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->dst_fbo
));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This
->resources
)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
182 dumpResources(&This
->resources
);
185 if(This
->contexts
) ERR("Context array not freed!\n");
186 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
187 This
->haveHardwareCursor
= FALSE
;
189 IWineD3D_Release(This
->wineD3D
);
190 This
->wineD3D
= NULL
;
191 HeapFree(GetProcessHeap(), 0, This
);
192 TRACE("Freed device %p\n", This
);
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
202 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
203 *pParent
= This
->parent
;
204 IUnknown_AddRef(This
->parent
);
208 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
209 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
211 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
212 IWineD3DVertexBufferImpl
*object
;
213 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
214 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer
= NULL
;
220 return WINED3DERR_INVALIDCALL
;
221 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer
= NULL
;
227 return WINED3DERR_INVALIDCALL
;
230 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
232 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
);
233 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion
<= 7 && conv
) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
262 object
->Flags
|= VBFLAG_CREATEVBO
;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
268 GLenum error
, glUsage
;
269 TRACE("Creating VBO for Index Buffer %p\n", object
);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
282 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
283 error
= glGetError();
284 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
290 error
= glGetError();
291 if(error
!= GL_NO_ERROR
) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage
= GL_STATIC_DRAW_ARB
;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
301 error
= glGetError();
302 if(error
!= GL_NO_ERROR
) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
307 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
317 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
318 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
319 HANDLE
*sharedHandle
, IUnknown
*parent
) {
320 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
321 IWineD3DIndexBufferImpl
*object
;
322 TRACE("(%p) Creating index buffer\n", This
);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
327 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
328 CreateIndexBufferVBO(This
, object
);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
332 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
333 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
338 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
340 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
341 IWineD3DStateBlockImpl
*object
;
345 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
346 object
->blockType
= Type
;
348 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
349 list_init(&object
->lightMap
[i
]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type
== WINED3DSBT_INIT
) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
360 temp_result
= allocate_shader_constants(object
);
361 if (WINED3D_OK
!= temp_result
)
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This
->stateBlock
!= NULL
)
366 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
368 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
370 /* Reset the ref and type after kludging it */
371 object
->wineD3DDevice
= This
;
373 object
->blockType
= Type
;
375 TRACE("Updating changed flags appropriate for type %d\n", Type
);
377 if (Type
== WINED3DSBT_ALL
) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
382 /* Lights are not part of the changed / set structure */
383 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
385 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
386 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
387 light
->changed
= TRUE
;
388 light
->enabledChanged
= TRUE
;
391 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
392 object
->contained_render_states
[j
- 1] = j
;
394 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
397 object
->contained_transform_states
[j
- 1] = j
;
399 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
400 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
401 object
->contained_vs_consts_f
[j
] = j
;
403 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
404 for(j
= 0; j
< MAX_CONST_I
; j
++) {
405 object
->contained_vs_consts_i
[j
] = j
;
407 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
408 for(j
= 0; j
< MAX_CONST_B
; j
++) {
409 object
->contained_vs_consts_b
[j
] = j
;
411 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
412 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
413 object
->contained_ps_consts_f
[j
] = j
;
415 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
416 for(j
= 0; j
< MAX_CONST_I
; j
++) {
417 object
->contained_ps_consts_i
[j
] = j
;
419 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
420 for(j
= 0; j
< MAX_CONST_B
; j
++) {
421 object
->contained_ps_consts_b
[j
] = j
;
423 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
424 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
425 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
426 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
427 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
428 object
->num_contained_tss_states
++;
431 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
432 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
433 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
434 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
435 object
->num_contained_sampler_states
++;
439 for(i
= 0; i
< MAX_STREAMS
; i
++) {
440 if(object
->streamSource
[i
]) {
441 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
444 if(object
->pIndexData
) {
445 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
447 if(object
->vertexShader
) {
448 IWineD3DVertexShader_AddRef(object
->vertexShader
);
450 if(object
->pixelShader
) {
451 IWineD3DPixelShader_AddRef(object
->pixelShader
);
454 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
459 object
->changed
.pixelShader
= TRUE
;
461 /* Pixel Shader Constants */
462 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
) {
463 object
->contained_ps_consts_f
[i
] = i
;
464 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
466 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
467 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
468 object
->contained_ps_consts_b
[i
] = i
;
469 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
471 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
472 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
473 object
->contained_ps_consts_i
[i
] = i
;
474 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
476 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
478 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
479 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
480 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
482 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
483 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
484 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
485 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
486 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
487 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
488 object
->num_contained_tss_states
++;
491 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
492 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
493 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
494 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
495 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
496 object
->num_contained_sampler_states
++;
499 if(object
->pixelShader
) {
500 IWineD3DPixelShader_AddRef(object
->pixelShader
);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i
= 0; i
< MAX_STREAMS
; i
++) {
507 object
->streamSource
[i
] = NULL
;
509 object
->pIndexData
= NULL
;
510 object
->vertexShader
= NULL
;
512 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
517 object
->changed
.vertexShader
= TRUE
;
519 /* Vertex Shader Constants */
520 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
521 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
522 object
->contained_vs_consts_f
[i
] = i
;
524 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
525 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
526 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
527 object
->contained_vs_consts_b
[i
] = i
;
529 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
530 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
531 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
532 object
->contained_vs_consts_i
[i
] = i
;
534 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
535 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
536 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
537 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
539 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
540 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
541 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
542 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
543 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
544 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
545 object
->num_contained_tss_states
++;
548 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
549 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
550 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
551 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
552 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
553 object
->num_contained_sampler_states
++;
557 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
559 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
560 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
561 light
->changed
= TRUE
;
562 light
->enabledChanged
= TRUE
;
566 for(i
= 0; i
< MAX_STREAMS
; i
++) {
567 if(object
->streamSource
[i
]) {
568 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
571 if(object
->vertexShader
) {
572 IWineD3DVertexShader_AddRef(object
->vertexShader
);
574 object
->pIndexData
= NULL
;
575 object
->pixelShader
= NULL
;
577 FIXME("Unrecognized state block type %d\n", Type
);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
584 /* ************************************
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 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.
593 ******************************** */
595 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
) {
596 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
597 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size
= 1;
599 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, NULL
, NULL
);
600 TRACE("(%p) Create surface\n",This
);
602 /** FIXME: Check ranges on the inputs are valid
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
610 *******************************/
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality
> 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
626 MultisampleQuality
=0;
629 /** FIXME: Check that the format is supported
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
636 *********************************/
637 if (WINED3DFMT_UNKNOWN
== Format
) {
639 } else if (Format
== WINED3DFMT_DXT1
) {
640 /* DXT1 is half byte per pixel */
641 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
643 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
644 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
||
645 Format
== WINED3DFMT_ATI2N
) {
646 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
648 /* The pitch is a multiple of 4 bytes */
649 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
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
;
665 object
->Flags
= SFLAG_NORMCOORD
; /* Default to normalized coords */
666 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
667 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
668 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
671 if (WINED3DFMT_UNKNOWN
!= Format
) {
672 object
->bytesPerPixel
= tableEntry
->bpp
;
674 object
->bytesPerPixel
= 0;
677 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
679 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
681 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
682 * this function is too deep to need to care about things like this.
683 * Levels need to be checked too, and possibly Type since they all affect what can be done.
684 * ****************************************/
686 case WINED3DPOOL_SCRATCH
:
688 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
689 "which are mutually exclusive, setting lockable to TRUE\n");
692 case WINED3DPOOL_SYSTEMMEM
:
693 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
694 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
695 case WINED3DPOOL_MANAGED
:
696 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
697 "Usage of DYNAMIC which are mutually exclusive, not doing "
698 "anything just telling you.\n");
700 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
701 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
702 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
703 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
706 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
710 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
711 FIXME("Trying to create a render target that isn't in the default pool\n");
714 /* mark the texture as dirty so that it gets loaded first time around*/
715 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
716 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
717 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
718 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
720 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
721 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
722 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
724 /* Look at the implementation and set the correct Vtable */
727 /* Check if a 3D adapter is available when creating gl surfaces */
729 ERR("OpenGL surfaces are not available without opengl\n");
730 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
731 HeapFree(GetProcessHeap(), 0, object
);
732 return WINED3DERR_NOTAVAILABLE
;
737 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
741 /* To be sure to catch this */
742 ERR("Unknown requested surface implementation %d!\n", Impl
);
743 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
744 return WINED3DERR_INVALIDCALL
;
747 list_init(&object
->renderbuffers
);
749 /* Call the private setup routine */
750 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
754 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
755 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
756 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
757 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
759 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
760 IWineD3DTextureImpl
*object
;
765 unsigned int pow2Width
;
766 unsigned int pow2Height
;
767 const GlPixelFormatDesc
*glDesc
;
768 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
770 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
771 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
772 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
774 /* TODO: It should only be possible to create textures for formats
775 that are reported as supported */
776 if (WINED3DFMT_UNKNOWN
>= Format
) {
777 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
778 return WINED3DERR_INVALIDCALL
;
781 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
782 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
783 object
->width
= Width
;
784 object
->height
= Height
;
786 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
787 object
->baseTexture
.minMipLookup
= &minMipLookup
;
788 object
->baseTexture
.magLookup
= &magLookup
;
790 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
791 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
794 /** Non-power2 support **/
795 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
799 /* Find the nearest pow2 match */
800 pow2Width
= pow2Height
= 1;
801 while (pow2Width
< Width
) pow2Width
<<= 1;
802 while (pow2Height
< Height
) pow2Height
<<= 1;
804 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
806 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
807 HeapFree(GetProcessHeap(), 0, object
);
809 return WINED3DERR_INVALIDCALL
;
816 /** FIXME: add support for real non-power-two if it's provided by the video card **/
817 /* Precalculated scaling for 'faked' non power of two texture coords.
818 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
819 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
820 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
822 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT
) && (Width
!= pow2Width
|| Height
!= pow2Height
)) {
823 object
->baseTexture
.pow2Matrix
[0] = 1.0;
824 object
->baseTexture
.pow2Matrix
[5] = 1.0;
825 object
->baseTexture
.pow2Matrix
[10] = 1.0;
826 object
->baseTexture
.pow2Matrix
[15] = 1.0;
827 object
->target
= GL_TEXTURE_2D
;
828 object
->cond_np2
= TRUE
;
831 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
832 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
833 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
834 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
836 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
837 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
838 object
->baseTexture
.pow2Matrix
[10] = 1.0;
839 object
->baseTexture
.pow2Matrix
[15] = 1.0;
840 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
841 object
->cond_np2
= TRUE
;
842 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
844 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
845 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
846 object
->baseTexture
.pow2Matrix
[10] = 1.0;
847 object
->baseTexture
.pow2Matrix
[15] = 1.0;
848 object
->target
= GL_TEXTURE_2D
;
849 object
->cond_np2
= FALSE
;
851 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
853 /* Calculate levels for mip mapping */
854 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
855 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
856 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
857 return WINED3DERR_INVALIDCALL
;
860 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
861 return WINED3DERR_INVALIDCALL
;
863 object
->baseTexture
.levels
= 1;
864 } else if (Levels
== 0) {
865 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
866 object
->baseTexture
.levels
++;
869 while (tmpW
> 1 || tmpH
> 1) {
870 tmpW
= max(1, tmpW
>> 1);
871 tmpH
= max(1, tmpH
>> 1);
872 object
->baseTexture
.levels
++;
874 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
877 /* Generate all the surfaces */
880 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
882 /* use the callback to create the texture surface */
883 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
884 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
885 FIXME("Failed to create surface %p\n", object
);
887 object
->surfaces
[i
] = NULL
;
888 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
894 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
895 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
896 /* calculate the next mipmap level */
897 tmpW
= max(1, tmpW
>> 1);
898 tmpH
= max(1, tmpH
>> 1);
900 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
902 TRACE("(%p) : Created texture %p\n", This
, object
);
906 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
907 UINT Width
, UINT Height
, UINT Depth
,
908 UINT Levels
, DWORD Usage
,
909 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
910 IWineD3DVolumeTexture
**ppVolumeTexture
,
911 HANDLE
*pSharedHandle
, IUnknown
*parent
,
912 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
914 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
915 IWineD3DVolumeTextureImpl
*object
;
920 const GlPixelFormatDesc
*glDesc
;
922 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
924 /* TODO: It should only be possible to create textures for formats
925 that are reported as supported */
926 if (WINED3DFMT_UNKNOWN
>= Format
) {
927 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
928 return WINED3DERR_INVALIDCALL
;
930 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
931 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
932 return WINED3DERR_INVALIDCALL
;
935 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
936 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
938 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
939 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
941 object
->width
= Width
;
942 object
->height
= Height
;
943 object
->depth
= Depth
;
945 /* Is NP2 support for volumes needed? */
946 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
947 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
948 object
->baseTexture
.pow2Matrix
[10] = 1.0;
949 object
->baseTexture
.pow2Matrix
[15] = 1.0;
951 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
952 object
->baseTexture
.minMipLookup
= &minMipLookup
;
953 object
->baseTexture
.magLookup
= &magLookup
;
955 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
956 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
959 /* Calculate levels for mip mapping */
960 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
961 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
962 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
963 return WINED3DERR_INVALIDCALL
;
966 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
967 return WINED3DERR_INVALIDCALL
;
970 } else if (Levels
== 0) {
971 object
->baseTexture
.levels
++;
975 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
976 tmpW
= max(1, tmpW
>> 1);
977 tmpH
= max(1, tmpH
>> 1);
978 tmpD
= max(1, tmpD
>> 1);
979 object
->baseTexture
.levels
++;
981 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
984 /* Generate all the surfaces */
989 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
992 /* Create the volume */
993 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
994 &object
->volumes
[i
], pSharedHandle
);
997 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
998 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
999 *ppVolumeTexture
= NULL
;
1003 /* Set its container to this object */
1004 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1006 /* calculate the next mipmap level */
1007 tmpW
= max(1, tmpW
>> 1);
1008 tmpH
= max(1, tmpH
>> 1);
1009 tmpD
= max(1, tmpD
>> 1);
1011 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1013 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1014 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1018 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1019 UINT Width
, UINT Height
, UINT Depth
,
1021 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1022 IWineD3DVolume
** ppVolume
,
1023 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1025 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1026 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1027 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1029 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1030 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1031 return WINED3DERR_INVALIDCALL
;
1034 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1036 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1037 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1039 object
->currentDesc
.Width
= Width
;
1040 object
->currentDesc
.Height
= Height
;
1041 object
->currentDesc
.Depth
= Depth
;
1042 object
->bytesPerPixel
= formatDesc
->bpp
;
1044 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1045 object
->lockable
= TRUE
;
1046 object
->locked
= FALSE
;
1047 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1048 object
->dirty
= TRUE
;
1050 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1053 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1054 UINT Levels
, DWORD Usage
,
1055 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1056 IWineD3DCubeTexture
**ppCubeTexture
,
1057 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1058 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1060 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1061 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1065 unsigned int pow2EdgeLength
= EdgeLength
;
1066 const GlPixelFormatDesc
*glDesc
;
1067 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1069 /* TODO: It should only be possible to create textures for formats
1070 that are reported as supported */
1071 if (WINED3DFMT_UNKNOWN
>= Format
) {
1072 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1073 return WINED3DERR_INVALIDCALL
;
1076 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1077 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1078 return WINED3DERR_INVALIDCALL
;
1081 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1082 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1084 TRACE("(%p) Create Cube Texture\n", This
);
1086 /** Non-power2 support **/
1088 /* Find the nearest pow2 match */
1090 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1092 object
->edgeLength
= EdgeLength
;
1093 /* TODO: support for native non-power 2 */
1094 /* Precalculated scaling for 'faked' non power of two texture coords */
1095 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1096 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1097 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1098 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1100 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
1101 object
->baseTexture
.minMipLookup
= &minMipLookup
;
1102 object
->baseTexture
.magLookup
= &magLookup
;
1104 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
1105 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
1108 /* Calculate levels for mip mapping */
1109 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object
);
1113 *ppCubeTexture
= NULL
;
1115 return WINED3DERR_INVALIDCALL
;
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object
);
1120 *ppCubeTexture
= NULL
;
1122 return WINED3DERR_INVALIDCALL
;
1125 } else if (Levels
== 0) {
1126 object
->baseTexture
.levels
++;
1129 tmpW
= max(1, tmpW
>> 1);
1130 object
->baseTexture
.levels
++;
1132 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1135 /* Generate all the surfaces */
1137 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1139 /* Create the 6 faces */
1140 for (j
= 0; j
< 6; j
++) {
1142 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1143 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1145 if(hr
!= WINED3D_OK
) {
1149 for (l
= 0; l
< j
; l
++) {
1150 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1152 for (k
= 0; k
< i
; k
++) {
1153 for (l
= 0; l
< 6; l
++) {
1154 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1158 FIXME("(%p) Failed to create surface\n",object
);
1159 HeapFree(GetProcessHeap(),0,object
);
1160 *ppCubeTexture
= NULL
;
1163 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1164 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1166 tmpW
= max(1, tmpW
>> 1);
1168 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1170 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1171 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1175 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1176 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1177 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1178 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1179 const IWineD3DQueryVtbl
*vtable
;
1181 /* Just a check to see if we support this type of query */
1183 case WINED3DQUERYTYPE_OCCLUSION
:
1184 TRACE("(%p) occlusion query\n", This
);
1185 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1188 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1190 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1193 case WINED3DQUERYTYPE_EVENT
:
1194 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1195 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1196 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1198 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1200 vtable
= &IWineD3DEventQuery_Vtbl
;
1204 case WINED3DQUERYTYPE_VCACHE
:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1206 case WINED3DQUERYTYPE_VERTEXSTATS
:
1207 case WINED3DQUERYTYPE_TIMESTAMP
:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1217 /* Use the base Query vtable until we have a special one for each query */
1218 vtable
= &IWineD3DQuery_Vtbl
;
1219 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1221 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1225 D3DCREATEOBJECTINSTANCE(object
, Query
)
1226 object
->lpVtbl
= vtable
;
1227 object
->type
= Type
;
1228 object
->state
= QUERY_CREATED
;
1229 /* allocated the 'extended' data based on the type of query requested */
1231 case WINED3DQUERYTYPE_OCCLUSION
:
1232 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1233 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1235 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1236 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1237 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1240 case WINED3DQUERYTYPE_EVENT
:
1241 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1242 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1244 if(GL_SUPPORT(APPLE_FENCE
)) {
1245 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1246 checkGLcall("glGenFencesAPPLE");
1247 } else if(GL_SUPPORT(NV_FENCE
)) {
1248 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1249 checkGLcall("glGenFencesNV");
1253 case WINED3DQUERYTYPE_VCACHE
:
1254 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1255 case WINED3DQUERYTYPE_VERTEXSTATS
:
1256 case WINED3DQUERYTYPE_TIMESTAMP
:
1257 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1258 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1259 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1260 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1261 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1262 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1263 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1264 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1266 object
->extendedData
= 0;
1267 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1269 TRACE("(%p) : Created Query %p\n", This
, object
);
1273 /*****************************************************************************
1274 * IWineD3DDeviceImpl_SetupFullscreenWindow
1276 * Helper function that modifies a HWND's Style and ExStyle for proper
1280 * iface: Pointer to the IWineD3DDevice interface
1281 * window: Window to setup
1283 *****************************************************************************/
1284 static LONG
fullscreen_style(LONG orig_style
) {
1285 LONG style
= orig_style
;
1286 style
&= ~WS_CAPTION
;
1287 style
&= ~WS_THICKFRAME
;
1289 /* Make sure the window is managed, otherwise we won't get keyboard input */
1290 style
|= WS_POPUP
| WS_SYSMENU
;
1295 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1296 LONG exStyle
= orig_exStyle
;
1298 /* Filter out window decorations */
1299 exStyle
&= ~WS_EX_WINDOWEDGE
;
1300 exStyle
&= ~WS_EX_CLIENTEDGE
;
1305 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1306 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1308 LONG style
, exStyle
;
1309 /* Don't do anything if an original style is stored.
1310 * That shouldn't happen
1312 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1313 if (This
->style
|| This
->exStyle
) {
1314 ERR("(%p): Want to change the window parameters of HWND %p, but "
1315 "another style is stored for restoration afterwards\n", This
, window
);
1318 /* Get the parameters and save them */
1319 style
= GetWindowLongW(window
, GWL_STYLE
);
1320 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1321 This
->style
= style
;
1322 This
->exStyle
= exStyle
;
1324 style
= fullscreen_style(style
);
1325 exStyle
= fullscreen_exStyle(exStyle
);
1327 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1328 This
->style
, This
->exStyle
, style
, exStyle
);
1330 SetWindowLongW(window
, GWL_STYLE
, style
);
1331 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1333 /* Inform the window about the update. */
1334 SetWindowPos(window
, HWND_TOP
, 0, 0,
1335 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1336 ShowWindow(window
, SW_NORMAL
);
1339 /*****************************************************************************
1340 * IWineD3DDeviceImpl_RestoreWindow
1342 * Helper function that restores a windows' properties when taking it out
1343 * of fullscreen mode
1346 * iface: Pointer to the IWineD3DDevice interface
1347 * window: Window to setup
1349 *****************************************************************************/
1350 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1351 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1352 LONG style
, exStyle
;
1354 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1355 * switch, do nothing
1357 if (!This
->style
&& !This
->exStyle
) return;
1359 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1360 This
, window
, This
->style
, This
->exStyle
);
1362 style
= GetWindowLongW(window
, GWL_STYLE
);
1363 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1365 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1366 * Some applications change it before calling Reset() when switching between windowed and
1367 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1369 if(style
== fullscreen_style(This
->style
) &&
1370 exStyle
== fullscreen_style(This
->exStyle
)) {
1371 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1372 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1375 /* Delete the old values */
1379 /* Inform the window about the update */
1380 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1381 0, 0, 0, 0, /* Pos, Size, ignored */
1382 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1385 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1386 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1388 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1389 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1390 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1393 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1394 HRESULT hr
= WINED3D_OK
;
1395 IUnknown
*bufferParent
;
1396 BOOL displaymode_set
= FALSE
;
1397 WINED3DDISPLAYMODE Mode
;
1398 const StaticPixelFormatDesc
*formatDesc
;
1400 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1402 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1403 * does a device hold a reference to a swap chain giving them a lifetime of the device
1404 * or does the swap chain notify the device of its destruction.
1405 *******************************/
1407 /* Check the params */
1408 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1409 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1410 return WINED3DERR_INVALIDCALL
;
1411 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1412 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");
1415 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1417 /*********************
1418 * Lookup the window Handle and the relating X window handle
1419 ********************/
1421 /* Setup hwnd we are using, plus which display this equates to */
1422 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1423 if (!object
->win_handle
) {
1424 object
->win_handle
= This
->createParms
.hFocusWindow
;
1426 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, object
->win_handle
);
1428 hDc
= GetDC(object
->win_handle
);
1429 TRACE("Using hDc %p\n", hDc
);
1432 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1433 return WINED3DERR_NOTAVAILABLE
;
1436 /* Get info on the current display setup */
1437 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1438 object
->orig_width
= Mode
.Width
;
1439 object
->orig_height
= Mode
.Height
;
1440 object
->orig_fmt
= Mode
.Format
;
1441 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1443 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1444 * then the corresponding dimension of the client area of the hDeviceWindow
1445 * (or the focus window, if hDeviceWindow is NULL) is taken.
1446 **********************/
1448 if (pPresentationParameters
->Windowed
&&
1449 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1450 (pPresentationParameters
->BackBufferHeight
== 0) ||
1451 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1454 GetClientRect(object
->win_handle
, &Rect
);
1456 if (pPresentationParameters
->BackBufferWidth
== 0) {
1457 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1458 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1460 if (pPresentationParameters
->BackBufferHeight
== 0) {
1461 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1462 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1464 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1465 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1466 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1470 /* Put the correct figures in the presentation parameters */
1471 TRACE("Copying across presentation parameters\n");
1472 object
->presentParms
= *pPresentationParameters
;
1474 TRACE("calling rendertarget CB\n");
1475 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1477 object
->presentParms
.BackBufferWidth
,
1478 object
->presentParms
.BackBufferHeight
,
1479 object
->presentParms
.BackBufferFormat
,
1480 object
->presentParms
.MultiSampleType
,
1481 object
->presentParms
.MultiSampleQuality
,
1482 TRUE
/* Lockable */,
1483 &object
->frontBuffer
,
1484 NULL
/* pShared (always null)*/);
1485 if (object
->frontBuffer
!= NULL
) {
1486 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1487 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1489 ERR("Failed to create the front buffer\n");
1493 /*********************
1494 * Windowed / Fullscreen
1495 *******************/
1498 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1499 * so we should really check to see if there is a fullscreen swapchain already
1500 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1501 **************************************/
1503 if (!pPresentationParameters
->Windowed
) {
1504 WINED3DDISPLAYMODE mode
;
1507 /* Change the display settings */
1508 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1509 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1510 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1511 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1513 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1514 displaymode_set
= TRUE
;
1515 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1519 * Create an opengl context for the display visual
1520 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1521 * use different properties after that point in time. FIXME: How to handle when requested format
1522 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1523 * it chooses is identical to the one already being used!
1524 **********************************/
1525 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1527 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1528 if(!object
->context
)
1529 return E_OUTOFMEMORY
;
1530 object
->num_contexts
= 1;
1532 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1533 if (!object
->context
[0]) {
1534 ERR("Failed to create a new context\n");
1535 hr
= WINED3DERR_NOTAVAILABLE
;
1538 TRACE("Context created (HWND=%p, glContext=%p)\n",
1539 object
->win_handle
, object
->context
[0]->glCtx
);
1542 /*********************
1543 * Create the back, front and stencil buffers
1544 *******************/
1545 if(object
->presentParms
.BackBufferCount
> 0) {
1548 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1549 if(!object
->backBuffer
) {
1550 ERR("Out of memory\n");
1555 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1556 TRACE("calling rendertarget CB\n");
1557 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1559 object
->presentParms
.BackBufferWidth
,
1560 object
->presentParms
.BackBufferHeight
,
1561 object
->presentParms
.BackBufferFormat
,
1562 object
->presentParms
.MultiSampleType
,
1563 object
->presentParms
.MultiSampleQuality
,
1564 TRUE
/* Lockable */,
1565 &object
->backBuffer
[i
],
1566 NULL
/* pShared (always null)*/);
1567 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1568 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1570 ERR("Cannot create new back buffer\n");
1574 glDrawBuffer(GL_BACK
);
1575 checkGLcall("glDrawBuffer(GL_BACK)");
1579 object
->backBuffer
= NULL
;
1581 /* Single buffering - draw to front buffer */
1583 glDrawBuffer(GL_FRONT
);
1584 checkGLcall("glDrawBuffer(GL_FRONT)");
1588 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1589 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1590 TRACE("Creating depth stencil buffer\n");
1591 if (This
->auto_depth_stencil_buffer
== NULL
) {
1592 hr
= D3DCB_CreateDepthStencil(This
->parent
,
1594 object
->presentParms
.BackBufferWidth
,
1595 object
->presentParms
.BackBufferHeight
,
1596 object
->presentParms
.AutoDepthStencilFormat
,
1597 object
->presentParms
.MultiSampleType
,
1598 object
->presentParms
.MultiSampleQuality
,
1599 FALSE
/* FIXME: Discard */,
1600 &This
->auto_depth_stencil_buffer
,
1601 NULL
/* pShared (always null)*/ );
1602 if (This
->auto_depth_stencil_buffer
!= NULL
)
1603 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1606 /** TODO: A check on width, height and multisample types
1607 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1608 ****************************/
1609 object
->wantsDepthStencilBuffer
= TRUE
;
1611 object
->wantsDepthStencilBuffer
= FALSE
;
1614 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1616 TRACE("Created swapchain %p\n", object
);
1617 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1621 if (displaymode_set
) {
1625 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1628 /* Change the display settings */
1629 memset(&devmode
, 0, sizeof(devmode
));
1630 devmode
.dmSize
= sizeof(devmode
);
1631 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1632 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1633 devmode
.dmPelsWidth
= object
->orig_width
;
1634 devmode
.dmPelsHeight
= object
->orig_height
;
1635 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1638 if (object
->backBuffer
) {
1640 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1641 if(object
->backBuffer
[i
]) {
1642 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1643 IUnknown_Release(bufferParent
); /* once for the get parent */
1644 if (IUnknown_Release(bufferParent
) > 0) {
1645 FIXME("(%p) Something's still holding the back buffer\n",This
);
1649 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1650 object
->backBuffer
= NULL
;
1652 if(object
->context
[0])
1653 DestroyContext(This
, object
->context
[0]);
1654 if(object
->frontBuffer
) {
1655 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1656 IUnknown_Release(bufferParent
); /* once for the get parent */
1657 if (IUnknown_Release(bufferParent
) > 0) {
1658 FIXME("(%p) Something's still holding the front buffer\n",This
);
1661 HeapFree(GetProcessHeap(), 0, object
);
1665 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1666 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1667 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1668 TRACE("(%p)\n", This
);
1670 return This
->NumberOfSwapChains
;
1673 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1674 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1675 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1677 if(iSwapChain
< This
->NumberOfSwapChains
) {
1678 *pSwapChain
= This
->swapchains
[iSwapChain
];
1679 IWineD3DSwapChain_AddRef(*pSwapChain
);
1680 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1683 TRACE("Swapchain out of range\n");
1685 return WINED3DERR_INVALIDCALL
;
1690 * Vertex Declaration
1692 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1693 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
1694 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1695 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1696 HRESULT hr
= WINED3D_OK
;
1698 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1699 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1701 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1703 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1705 *ppVertexDeclaration
= NULL
;
1706 HeapFree(GetProcessHeap(), 0, object
);
1712 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1713 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1715 unsigned int idx
, idx2
;
1716 unsigned int offset
;
1717 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1718 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1719 BOOL has_blend_idx
= has_blend
&&
1720 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1721 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1722 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1723 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1724 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1725 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1726 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1728 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1729 DWORD texcoords
= (fvf
& 0x00FF0000) >> 16;
1731 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1732 WINED3DVERTEXELEMENT
*elements
= NULL
;
1735 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1736 if (has_blend_idx
) num_blends
--;
1738 /* Compute declaration size */
1739 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1740 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1742 /* convert the declaration */
1743 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1747 elements
[size
-1] = end_element
;
1750 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1751 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1752 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1755 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1756 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1758 elements
[idx
].UsageIndex
= 0;
1761 if (has_blend
&& (num_blends
> 0)) {
1762 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1763 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1765 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1766 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1767 elements
[idx
].UsageIndex
= 0;
1770 if (has_blend_idx
) {
1771 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1772 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1773 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1774 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1775 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1777 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1778 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1779 elements
[idx
].UsageIndex
= 0;
1783 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1784 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1785 elements
[idx
].UsageIndex
= 0;
1789 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1790 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1791 elements
[idx
].UsageIndex
= 0;
1795 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1796 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1797 elements
[idx
].UsageIndex
= 0;
1801 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1802 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1803 elements
[idx
].UsageIndex
= 1;
1806 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1807 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1808 switch (numcoords
) {
1809 case WINED3DFVF_TEXTUREFORMAT1
:
1810 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1812 case WINED3DFVF_TEXTUREFORMAT2
:
1813 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1815 case WINED3DFVF_TEXTUREFORMAT3
:
1816 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1818 case WINED3DFVF_TEXTUREFORMAT4
:
1819 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1822 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1823 elements
[idx
].UsageIndex
= idx2
;
1827 /* Now compute offsets, and initialize the rest of the fields */
1828 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1829 elements
[idx
].Stream
= 0;
1830 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1831 elements
[idx
].Offset
= offset
;
1832 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1835 *ppVertexElements
= elements
;
1839 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1840 WINED3DVERTEXELEMENT
* elements
= NULL
;
1841 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1845 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1846 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1848 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1849 HeapFree(GetProcessHeap(), 0, elements
);
1850 if (hr
!= S_OK
) return hr
;
1855 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1856 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1857 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1858 HRESULT hr
= WINED3D_OK
;
1859 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1860 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1862 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1864 if (vertex_declaration
) {
1865 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1868 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1870 if (WINED3D_OK
!= hr
) {
1871 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1872 IWineD3DVertexShader_Release(*ppVertexShader
);
1873 return WINED3DERR_INVALIDCALL
;
1875 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1880 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1881 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1882 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1883 HRESULT hr
= WINED3D_OK
;
1885 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1886 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1887 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1888 if (WINED3D_OK
== hr
) {
1889 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1890 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1892 WARN("(%p) : Failed to create pixel shader\n", This
);
1898 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1899 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1900 IWineD3DPaletteImpl
*object
;
1902 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1904 /* Create the new object */
1905 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1907 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1908 return E_OUTOFMEMORY
;
1911 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1913 object
->Flags
= Flags
;
1914 object
->parent
= Parent
;
1915 object
->wineD3DDevice
= This
;
1916 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1918 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1921 HeapFree( GetProcessHeap(), 0, object
);
1922 return E_OUTOFMEMORY
;
1925 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1927 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1931 *Palette
= (IWineD3DPalette
*) object
;
1936 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1940 HDC dcb
= NULL
, dcs
= NULL
;
1941 WINEDDCOLORKEY colorkey
;
1943 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1946 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1947 dcb
= CreateCompatibleDC(NULL
);
1949 SelectObject(dcb
, hbm
);
1953 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1954 * couldn't be loaded
1956 memset(&bm
, 0, sizeof(bm
));
1961 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1962 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1963 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1965 ERR("Wine logo requested, but failed to create surface\n");
1970 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1971 if(FAILED(hr
)) goto out
;
1972 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1973 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1975 colorkey
.dwColorSpaceLowValue
= 0;
1976 colorkey
.dwColorSpaceHighValue
= 0;
1977 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1979 /* Fill the surface with a white color to show that wined3d is there */
1980 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1993 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
1995 /* Under DirectX you can have texture stage operations even if no texture is
1996 bound, whereas opengl will only do texture operations when a valid texture is
1997 bound. We emulate this by creating dummy textures and binding them to each
1998 texture stage, but disable all stages by default. Hence if a stage is enabled
1999 then the default texture will kick in until replaced by a SetTexture call */
2002 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2003 /* The dummy texture does not have client storage backing */
2004 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2005 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2007 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2008 GLubyte white
= 255;
2010 /* Make appropriate texture active */
2011 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2012 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2013 checkGLcall("glActiveTextureARB");
2015 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2018 /* Generate an opengl texture name */
2019 glGenTextures(1, &This
->dummyTextureName
[i
]);
2020 checkGLcall("glGenTextures");
2021 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2023 /* Generate a dummy 2d texture (not using 1d because they cause many
2024 * DRI drivers fall back to sw) */
2025 This
->stateBlock
->textureDimensions
[i
] = GL_TEXTURE_2D
;
2026 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2027 checkGLcall("glBindTexture");
2029 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2030 checkGLcall("glTexImage2D");
2032 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2033 /* Reenable because if supported it is enabled by default */
2034 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2035 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2041 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2042 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2043 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2048 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
2049 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2050 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2052 /* TODO: Test if OpenGL is compiled in and loaded */
2054 TRACE("(%p) : Creating stateblock\n", This
);
2055 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2056 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2058 (IWineD3DStateBlock
**)&This
->stateBlock
,
2060 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2061 WARN("Failed to create stateblock\n");
2064 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2065 This
->updateStateBlock
= This
->stateBlock
;
2066 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2068 hr
= allocate_shader_constants(This
->updateStateBlock
);
2069 if (WINED3D_OK
!= hr
) {
2073 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2074 This
->fbo_color_attachments
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2075 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2077 This
->NumberOfPalettes
= 1;
2078 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
2079 if(!This
->palettes
|| !This
->render_targets
|| !This
->fbo_color_attachments
|| !This
->draw_buffers
) {
2080 ERR("Out of memory!\n");
2083 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2084 if(!This
->palettes
[0]) {
2085 ERR("Out of memory!\n");
2088 for (i
= 0; i
< 256; ++i
) {
2089 This
->palettes
[0][i
].peRed
= 0xFF;
2090 This
->palettes
[0][i
].peGreen
= 0xFF;
2091 This
->palettes
[0][i
].peBlue
= 0xFF;
2092 This
->palettes
[0][i
].peFlags
= 0xFF;
2094 This
->currentPalette
= 0;
2096 /* Initialize the texture unit mapping to a 1:1 mapping */
2097 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2098 if (state
< GL_LIMITS(fragment_samplers
)) {
2099 This
->texUnitMap
[state
] = state
;
2100 This
->rev_tex_unit_map
[state
] = state
;
2102 This
->texUnitMap
[state
] = -1;
2103 This
->rev_tex_unit_map
[state
] = -1;
2107 /* Setup the implicit swapchain */
2108 TRACE("Creating implicit swapchain\n");
2109 hr
=D3DCB_CreateAdditionalSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2110 if (FAILED(hr
) || !swapchain
) {
2111 WARN("Failed to create implicit swapchain\n");
2115 This
->NumberOfSwapChains
= 1;
2116 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2117 if(!This
->swapchains
) {
2118 ERR("Out of memory!\n");
2121 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2123 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2124 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2125 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2126 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2129 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2130 This
->render_targets
[0] = swapchain
->frontBuffer
;
2131 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2133 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2134 This
->activeContext
= swapchain
->context
[0];
2135 This
->lastThread
= GetCurrentThreadId();
2137 /* Depth Stencil support */
2138 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2139 if (NULL
!= This
->stencilBufferTarget
) {
2140 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2143 hr
= This
->shader_backend
->shader_alloc_private(iface
);
2145 TRACE("Shader private data couldn't be allocated\n");
2148 hr
= This
->frag_pipe
->alloc_private(iface
);
2150 TRACE("Fragment pipeline private data couldn't be allocated\n");
2154 /* Set up some starting GL setup */
2156 /* Setup all the devices defaults */
2157 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2158 create_dummy_textures(This
);
2163 IWineD3DImpl_CheckGraphicsMemory();
2166 { /* Set a default viewport */
2170 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2171 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2174 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2177 /* Initialize the current view state */
2178 This
->view_ident
= 1;
2179 This
->contexts
[0]->last_was_rhw
= 0;
2180 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2181 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2183 switch(wined3d_settings
.offscreen_rendering_mode
) {
2186 This
->offscreenBuffer
= GL_BACK
;
2189 case ORM_BACKBUFFER
:
2191 if(This
->activeContext
->aux_buffers
> 0) {
2192 TRACE("Using auxilliary buffer for offscreen rendering\n");
2193 This
->offscreenBuffer
= GL_AUX0
;
2195 TRACE("Using back buffer for offscreen rendering\n");
2196 This
->offscreenBuffer
= GL_BACK
;
2201 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2204 /* Clear the screen */
2205 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2206 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2209 This
->d3d_initialized
= TRUE
;
2211 if(wined3d_settings
.logo
) {
2212 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2214 This
->highest_dirty_ps_const
= 0;
2215 This
->highest_dirty_vs_const
= 0;
2219 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2220 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2221 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2222 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2223 This
->NumberOfSwapChains
= 0;
2224 if(This
->palettes
) {
2225 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2226 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2228 This
->NumberOfPalettes
= 0;
2230 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2232 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2233 if(This
->stateBlock
) {
2234 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2235 This
->stateBlock
= NULL
;
2237 This
->frag_pipe
->free_private(iface
);
2238 This
->shader_backend
->shader_free_private(iface
);
2242 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2243 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2246 TRACE("(%p)\n", This
);
2248 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2250 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2251 * it was created. Thus make sure a context is active for the glDelete* calls
2253 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2255 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2257 TRACE("Deleting high order patches\n");
2258 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2259 struct list
*e1
, *e2
;
2260 struct WineD3DRectPatch
*patch
;
2261 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2262 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2263 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2267 /* Delete the palette conversion shader if it is around */
2268 if(This
->paletteConversionShader
) {
2270 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2272 This
->paletteConversionShader
= 0;
2275 /* Delete the pbuffer context if there is any */
2276 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2278 /* Delete the mouse cursor texture */
2279 if(This
->cursorTexture
) {
2281 glDeleteTextures(1, &This
->cursorTexture
);
2283 This
->cursorTexture
= 0;
2286 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2287 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2289 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2290 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2293 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2294 * private data, it might contain opengl pointers
2296 if(This
->depth_blt_texture
) {
2297 glDeleteTextures(1, &This
->depth_blt_texture
);
2298 This
->depth_blt_texture
= 0;
2300 if (This
->depth_blt_rb
) {
2301 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2302 This
->depth_blt_rb
= 0;
2303 This
->depth_blt_rb_w
= 0;
2304 This
->depth_blt_rb_h
= 0;
2307 /* Release the update stateblock */
2308 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2309 if(This
->updateStateBlock
!= This
->stateBlock
)
2310 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2312 This
->updateStateBlock
= NULL
;
2314 { /* because were not doing proper internal refcounts releasing the primary state block
2315 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2316 to set this->stateBlock = NULL; first */
2317 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2318 This
->stateBlock
= NULL
;
2320 /* Release the stateblock */
2321 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2322 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2326 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2327 This
->frag_pipe
->free_private(iface
);
2328 This
->shader_backend
->shader_free_private(iface
);
2330 /* Release the buffers (with sanity checks)*/
2331 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2332 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2333 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2334 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2336 This
->stencilBufferTarget
= NULL
;
2338 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2339 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2340 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2342 TRACE("Setting rendertarget to NULL\n");
2343 This
->render_targets
[0] = NULL
;
2345 if (This
->auto_depth_stencil_buffer
) {
2346 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2347 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2349 This
->auto_depth_stencil_buffer
= NULL
;
2352 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2353 TRACE("Releasing the implicit swapchain %d\n", i
);
2354 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2355 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2359 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2360 This
->swapchains
= NULL
;
2361 This
->NumberOfSwapChains
= 0;
2363 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2364 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2365 This
->palettes
= NULL
;
2366 This
->NumberOfPalettes
= 0;
2368 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2369 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2370 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2371 This
->render_targets
= NULL
;
2372 This
->fbo_color_attachments
= NULL
;
2373 This
->draw_buffers
= NULL
;
2375 This
->d3d_initialized
= FALSE
;
2379 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2380 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2381 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2383 /* Setup the window for fullscreen mode */
2384 if(fullscreen
&& !This
->ddraw_fullscreen
) {
2385 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
2386 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
2387 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
2390 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2391 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2392 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2395 This
->ddraw_fullscreen
= fullscreen
;
2398 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2399 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2400 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2402 * There is no way to deactivate thread safety once it is enabled.
2404 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2405 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2407 /*For now just store the flag(needed in case of ddraw) */
2408 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2413 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2415 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2417 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2420 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2422 /* Resize the screen even without a window:
2423 * The app could have unset it with SetCooperativeLevel, but not called
2424 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2425 * but we don't have any hwnd
2428 memset(&devmode
, 0, sizeof(devmode
));
2429 devmode
.dmSize
= sizeof(devmode
);
2430 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2431 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2432 devmode
.dmPelsWidth
= pMode
->Width
;
2433 devmode
.dmPelsHeight
= pMode
->Height
;
2435 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2436 if (pMode
->RefreshRate
!= 0) {
2437 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2440 /* Only change the mode if necessary */
2441 if( (This
->ddraw_width
== pMode
->Width
) &&
2442 (This
->ddraw_height
== pMode
->Height
) &&
2443 (This
->ddraw_format
== pMode
->Format
) &&
2444 (pMode
->RefreshRate
== 0) ) {
2448 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2449 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2450 if(devmode
.dmDisplayFrequency
!= 0) {
2451 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2452 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2453 devmode
.dmDisplayFrequency
= 0;
2454 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2456 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2457 return WINED3DERR_NOTAVAILABLE
;
2461 /* Store the new values */
2462 This
->ddraw_width
= pMode
->Width
;
2463 This
->ddraw_height
= pMode
->Height
;
2464 This
->ddraw_format
= pMode
->Format
;
2466 /* Only do this with a window of course, and only if we're fullscreened */
2467 if(This
->ddraw_window
&& This
->ddraw_fullscreen
)
2468 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2470 /* And finally clip mouse to our screen */
2471 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2472 ClipCursor(&clip_rc
);
2477 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2478 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2479 *ppD3D
= This
->wineD3D
;
2480 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2481 IWineD3D_AddRef(*ppD3D
);
2485 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2486 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2488 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2489 (This
->adapter
->TextureRam
/(1024*1024)),
2490 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2491 /* return simulated texture memory left */
2492 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2500 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2501 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2503 /* Update the current state block */
2504 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2506 if(This
->updateStateBlock
->fvf
== fvf
) {
2507 TRACE("Application is setting the old fvf over, nothing to do\n");
2511 This
->updateStateBlock
->fvf
= fvf
;
2512 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2513 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2518 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2519 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2520 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2521 *pfvf
= This
->stateBlock
->fvf
;
2526 * Get / Set Stream Source
2528 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2529 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2530 IWineD3DVertexBuffer
*oldSrc
;
2532 if (StreamNumber
>= MAX_STREAMS
) {
2533 WARN("Stream out of range %d\n", StreamNumber
);
2534 return WINED3DERR_INVALIDCALL
;
2535 } else if(OffsetInBytes
& 0x3) {
2536 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2537 return WINED3DERR_INVALIDCALL
;
2540 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2541 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2543 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2545 if(oldSrc
== pStreamData
&&
2546 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2547 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2548 TRACE("Application is setting the old values over, nothing to do\n");
2552 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2554 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2555 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2558 /* Handle recording of state blocks */
2559 if (This
->isRecordingState
) {
2560 TRACE("Recording... not performing anything\n");
2561 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2562 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2566 /* Need to do a getParent and pass the references up */
2567 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2568 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2569 so for now, just count internally */
2570 if (pStreamData
!= NULL
) {
2571 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2572 InterlockedIncrement(&vbImpl
->bindCount
);
2573 IWineD3DVertexBuffer_AddRef(pStreamData
);
2575 if (oldSrc
!= NULL
) {
2576 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2577 IWineD3DVertexBuffer_Release(oldSrc
);
2580 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2585 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2586 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2588 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2589 This
->stateBlock
->streamSource
[StreamNumber
],
2590 This
->stateBlock
->streamOffset
[StreamNumber
],
2591 This
->stateBlock
->streamStride
[StreamNumber
]);
2593 if (StreamNumber
>= MAX_STREAMS
) {
2594 WARN("Stream out of range %d\n", StreamNumber
);
2595 return WINED3DERR_INVALIDCALL
;
2597 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2598 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2600 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2603 if (*pStream
!= NULL
) {
2604 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2609 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2610 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2611 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2612 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2614 /* Verify input at least in d3d9 this is invalid*/
2615 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2616 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2617 return WINED3DERR_INVALIDCALL
;
2619 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2620 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2621 return WINED3DERR_INVALIDCALL
;
2624 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2625 return WINED3DERR_INVALIDCALL
;
2628 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2629 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2631 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2632 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2634 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2635 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2636 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2642 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2643 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2645 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2646 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2648 TRACE("(%p) : returning %d\n", This
, *Divider
);
2654 * Get / Set & Multiply Transform
2656 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2657 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2659 /* Most of this routine, comments included copied from ddraw tree initially: */
2660 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2662 /* Handle recording of state blocks */
2663 if (This
->isRecordingState
) {
2664 TRACE("Recording... not performing anything\n");
2665 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2666 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2671 * If the new matrix is the same as the current one,
2672 * we cut off any further processing. this seems to be a reasonable
2673 * optimization because as was noticed, some apps (warcraft3 for example)
2674 * tend towards setting the same matrix repeatedly for some reason.
2676 * From here on we assume that the new matrix is different, wherever it matters.
2678 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2679 TRACE("The app is setting the same matrix over again\n");
2682 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2686 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2687 where ViewMat = Camera space, WorldMat = world space.
2689 In OpenGL, camera and world space is combined into GL_MODELVIEW
2690 matrix. The Projection matrix stay projection matrix.
2693 /* Capture the times we can just ignore the change for now */
2694 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2695 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2696 /* Handled by the state manager */
2699 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2703 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2704 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2705 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2706 *pMatrix
= This
->stateBlock
->transforms
[State
];
2710 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2711 WINED3DMATRIX
*mat
= NULL
;
2714 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2715 * below means it will be recorded in a state block change, but it
2716 * works regardless where it is recorded.
2717 * If this is found to be wrong, change to StateBlock.
2719 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2720 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2722 if (State
< HIGHEST_TRANSFORMSTATE
)
2724 mat
= &This
->updateStateBlock
->transforms
[State
];
2726 FIXME("Unhandled transform state!!\n");
2729 multiply_matrix(&temp
, mat
, pMatrix
);
2731 /* Apply change via set transform - will reapply to eg. lights this way */
2732 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2738 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2739 you can reference any indexes you want as long as that number max are enabled at any
2740 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2741 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2742 but when recording, just build a chain pretty much of commands to be replayed. */
2744 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2746 PLIGHTINFOEL
*object
= NULL
;
2747 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2750 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2751 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2753 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2757 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2758 return WINED3DERR_INVALIDCALL
;
2761 switch(pLight
->Type
) {
2762 case WINED3DLIGHT_POINT
:
2763 case WINED3DLIGHT_SPOT
:
2764 case WINED3DLIGHT_PARALLELPOINT
:
2765 case WINED3DLIGHT_GLSPOT
:
2766 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2769 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2770 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2771 return WINED3DERR_INVALIDCALL
;
2775 case WINED3DLIGHT_DIRECTIONAL
:
2776 /* Ignores attenuation */
2780 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2781 return WINED3DERR_INVALIDCALL
;
2784 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2785 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2786 if(object
->OriginalIndex
== Index
) break;
2791 TRACE("Adding new light\n");
2792 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2794 ERR("Out of memory error when allocating a light\n");
2795 return E_OUTOFMEMORY
;
2797 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2798 object
->glIndex
= -1;
2799 object
->OriginalIndex
= Index
;
2800 object
->changed
= TRUE
;
2803 /* Initialize the object */
2804 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
,
2805 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2806 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2807 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2808 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2809 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2810 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2812 /* Save away the information */
2813 object
->OriginalParms
= *pLight
;
2815 switch (pLight
->Type
) {
2816 case WINED3DLIGHT_POINT
:
2818 object
->lightPosn
[0] = pLight
->Position
.x
;
2819 object
->lightPosn
[1] = pLight
->Position
.y
;
2820 object
->lightPosn
[2] = pLight
->Position
.z
;
2821 object
->lightPosn
[3] = 1.0f
;
2822 object
->cutoff
= 180.0f
;
2826 case WINED3DLIGHT_DIRECTIONAL
:
2828 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2829 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2830 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2831 object
->lightPosn
[3] = 0.0;
2832 object
->exponent
= 0.0f
;
2833 object
->cutoff
= 180.0f
;
2836 case WINED3DLIGHT_SPOT
:
2838 object
->lightPosn
[0] = pLight
->Position
.x
;
2839 object
->lightPosn
[1] = pLight
->Position
.y
;
2840 object
->lightPosn
[2] = pLight
->Position
.z
;
2841 object
->lightPosn
[3] = 1.0;
2844 object
->lightDirn
[0] = pLight
->Direction
.x
;
2845 object
->lightDirn
[1] = pLight
->Direction
.y
;
2846 object
->lightDirn
[2] = pLight
->Direction
.z
;
2847 object
->lightDirn
[3] = 1.0;
2850 * opengl-ish and d3d-ish spot lights use too different models for the
2851 * light "intensity" as a function of the angle towards the main light direction,
2852 * so we only can approximate very roughly.
2853 * however spot lights are rather rarely used in games (if ever used at all).
2854 * furthermore if still used, probably nobody pays attention to such details.
2856 if (pLight
->Falloff
== 0) {
2857 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2858 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2859 * will always be 1.0 for both of them, and we don't have to care for the
2860 * rest of the rather complex calculation
2862 object
->exponent
= 0;
2864 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2865 if (rho
< 0.0001) rho
= 0.0001f
;
2866 object
->exponent
= -0.3/log(cos(rho
/2));
2868 if (object
->exponent
> 128.0) {
2869 object
->exponent
= 128.0;
2871 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2877 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2880 /* Update the live definitions if the light is currently assigned a glIndex */
2881 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2882 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2887 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2888 PLIGHTINFOEL
*lightInfo
= NULL
;
2889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2890 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2892 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2894 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2895 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2896 if(lightInfo
->OriginalIndex
== Index
) break;
2900 if (lightInfo
== NULL
) {
2901 TRACE("Light information requested but light not defined\n");
2902 return WINED3DERR_INVALIDCALL
;
2905 *pLight
= lightInfo
->OriginalParms
;
2910 * Get / Set Light Enable
2911 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2913 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2914 PLIGHTINFOEL
*lightInfo
= NULL
;
2915 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2916 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2918 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2920 /* Tests show true = 128...not clear why */
2921 Enable
= Enable
? 128: 0;
2923 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2924 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2925 if(lightInfo
->OriginalIndex
== Index
) break;
2928 TRACE("Found light: %p\n", lightInfo
);
2930 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2931 if (lightInfo
== NULL
) {
2933 TRACE("Light enabled requested but light not defined, so defining one!\n");
2934 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2936 /* Search for it again! Should be fairly quick as near head of list */
2937 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2938 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2939 if(lightInfo
->OriginalIndex
== Index
) break;
2942 if (lightInfo
== NULL
) {
2943 FIXME("Adding default lights has failed dismally\n");
2944 return WINED3DERR_INVALIDCALL
;
2948 lightInfo
->enabledChanged
= TRUE
;
2950 if(lightInfo
->glIndex
!= -1) {
2951 if(!This
->isRecordingState
) {
2952 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2955 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2956 lightInfo
->glIndex
= -1;
2958 TRACE("Light already disabled, nothing to do\n");
2960 lightInfo
->enabled
= FALSE
;
2962 lightInfo
->enabled
= TRUE
;
2963 if (lightInfo
->glIndex
!= -1) {
2965 TRACE("Nothing to do as light was enabled\n");
2968 /* Find a free gl light */
2969 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2970 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2971 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2972 lightInfo
->glIndex
= i
;
2976 if(lightInfo
->glIndex
== -1) {
2977 /* Our tests show that Windows returns D3D_OK in this situation, even with
2978 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2979 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2980 * as well for those lights.
2982 * TODO: Test how this affects rendering
2984 FIXME("Too many concurrently active lights\n");
2988 /* i == lightInfo->glIndex */
2989 if(!This
->isRecordingState
) {
2990 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2998 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
3000 PLIGHTINFOEL
*lightInfo
= NULL
;
3001 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3003 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3004 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3006 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3007 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3008 if(lightInfo
->OriginalIndex
== Index
) break;
3012 if (lightInfo
== NULL
) {
3013 TRACE("Light enabled state requested but light not defined\n");
3014 return WINED3DERR_INVALIDCALL
;
3016 /* true is 128 according to SetLightEnable */
3017 *pEnable
= lightInfo
->enabled
? 128 : 0;
3022 * Get / Set Clip Planes
3024 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3025 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3026 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3028 /* Validate Index */
3029 if (Index
>= GL_LIMITS(clipplanes
)) {
3030 TRACE("Application has requested clipplane this device doesn't support\n");
3031 return WINED3DERR_INVALIDCALL
;
3034 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
3036 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3037 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3038 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3039 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3040 TRACE("Application is setting old values over, nothing to do\n");
3044 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3045 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3046 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3047 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3049 /* Handle recording of state blocks */
3050 if (This
->isRecordingState
) {
3051 TRACE("Recording... not performing anything\n");
3055 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3060 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3061 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3062 TRACE("(%p) : for idx %d\n", This
, Index
);
3064 /* Validate Index */
3065 if (Index
>= GL_LIMITS(clipplanes
)) {
3066 TRACE("Application has requested clipplane this device doesn't support\n");
3067 return WINED3DERR_INVALIDCALL
;
3070 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3071 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3072 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3073 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3078 * Get / Set Clip Plane Status
3079 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3081 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3082 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3083 FIXME("(%p) : stub\n", This
);
3084 if (NULL
== pClipStatus
) {
3085 return WINED3DERR_INVALIDCALL
;
3087 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3088 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3092 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3093 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3094 FIXME("(%p) : stub\n", This
);
3095 if (NULL
== pClipStatus
) {
3096 return WINED3DERR_INVALIDCALL
;
3098 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3099 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3104 * Get / Set Material
3106 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3107 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3109 if (!pMaterial
) return WINED3DERR_INVALIDCALL
;
3111 This
->updateStateBlock
->changed
.material
= TRUE
;
3112 This
->updateStateBlock
->material
= *pMaterial
;
3114 /* Handle recording of state blocks */
3115 if (This
->isRecordingState
) {
3116 TRACE("Recording... not performing anything\n");
3120 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3124 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3125 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3126 *pMaterial
= This
->updateStateBlock
->material
;
3127 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3128 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3129 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3130 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3131 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3132 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3133 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3134 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3135 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3143 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3144 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3145 IWineD3DIndexBuffer
*oldIdxs
;
3147 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3148 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3150 This
->updateStateBlock
->changed
.indices
= TRUE
;
3151 This
->updateStateBlock
->pIndexData
= pIndexData
;
3153 /* Handle recording of state blocks */
3154 if (This
->isRecordingState
) {
3155 TRACE("Recording... not performing anything\n");
3156 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3157 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3161 if(oldIdxs
!= pIndexData
) {
3162 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3163 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3164 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3169 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3170 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3172 *ppIndexData
= This
->stateBlock
->pIndexData
;
3174 /* up ref count on ppindexdata */
3176 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3177 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3179 TRACE("(%p) No index data set\n", This
);
3181 TRACE("Returning %p\n", *ppIndexData
);
3186 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3187 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3188 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3189 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3191 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3192 TRACE("Application is setting the old value over, nothing to do\n");
3196 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3198 if (This
->isRecordingState
) {
3199 TRACE("Recording... not performing anything\n");
3202 /* The base vertex index affects the stream sources */
3203 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3207 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3208 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3209 TRACE("(%p) : base_index %p\n", This
, base_index
);
3211 *base_index
= This
->stateBlock
->baseVertexIndex
;
3213 TRACE("Returning %u\n", *base_index
);
3219 * Get / Set Viewports
3221 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3222 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3224 TRACE("(%p)\n", This
);
3225 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3226 This
->updateStateBlock
->viewport
= *pViewport
;
3228 /* Handle recording of state blocks */
3229 if (This
->isRecordingState
) {
3230 TRACE("Recording... not performing anything\n");
3234 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3235 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3237 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3242 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3243 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3244 TRACE("(%p)\n", This
);
3245 *pViewport
= This
->stateBlock
->viewport
;
3250 * Get / Set Render States
3251 * TODO: Verify against dx9 definitions
3253 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3255 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3256 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3258 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3260 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3261 This
->updateStateBlock
->renderState
[State
] = Value
;
3263 /* Handle recording of state blocks */
3264 if (This
->isRecordingState
) {
3265 TRACE("Recording... not performing anything\n");
3269 /* Compared here and not before the assignment to allow proper stateblock recording */
3270 if(Value
== oldValue
) {
3271 TRACE("Application is setting the old value over, nothing to do\n");
3273 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3279 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3280 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3281 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3282 *pValue
= This
->stateBlock
->renderState
[State
];
3287 * Get / Set Sampler States
3288 * TODO: Verify against dx9 definitions
3291 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3292 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3295 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3296 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3298 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3299 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3302 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3303 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3304 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3307 * SetSampler is designed to allow for more than the standard up to 8 textures
3308 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3309 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3311 * http://developer.nvidia.com/object/General_FAQ.html#t6
3313 * There are two new settings for GForce
3315 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3316 * and the texture one:
3317 * GL_MAX_TEXTURE_COORDS_ARB.
3318 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3321 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3322 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3323 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3325 /* Handle recording of state blocks */
3326 if (This
->isRecordingState
) {
3327 TRACE("Recording... not performing anything\n");
3331 if(oldValue
== Value
) {
3332 TRACE("Application is setting the old value over, nothing to do\n");
3336 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3341 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3342 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3344 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3345 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3347 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3348 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3351 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3352 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3353 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3355 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3356 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3361 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3362 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3364 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3365 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3366 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3369 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3371 if(This
->isRecordingState
) {
3372 TRACE("Recording... not performing anything\n");
3376 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3381 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3382 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3384 *pRect
= This
->updateStateBlock
->scissorRect
;
3385 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3389 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3390 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3391 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3393 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3395 This
->updateStateBlock
->vertexDecl
= pDecl
;
3396 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3398 if (This
->isRecordingState
) {
3399 TRACE("Recording... not performing anything\n");
3401 } else if(pDecl
== oldDecl
) {
3402 /* Checked after the assignment to allow proper stateblock recording */
3403 TRACE("Application is setting the old declaration over, nothing to do\n");
3407 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3411 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3412 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3414 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3416 *ppDecl
= This
->stateBlock
->vertexDecl
;
3417 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3421 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3422 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3423 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3425 This
->updateStateBlock
->vertexShader
= pShader
;
3426 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3428 if (This
->isRecordingState
) {
3429 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3430 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3431 TRACE("Recording... not performing anything\n");
3433 } else if(oldShader
== pShader
) {
3434 /* Checked here to allow proper stateblock recording */
3435 TRACE("App is setting the old shader over, nothing to do\n");
3439 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3440 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3441 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3443 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3448 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3449 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3451 if (NULL
== ppShader
) {
3452 return WINED3DERR_INVALIDCALL
;
3454 *ppShader
= This
->stateBlock
->vertexShader
;
3455 if( NULL
!= *ppShader
)
3456 IWineD3DVertexShader_AddRef(*ppShader
);
3458 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3462 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3463 IWineD3DDevice
*iface
,
3465 CONST BOOL
*srcData
,
3468 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3469 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3471 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3472 iface
, srcData
, start
, count
);
3474 if (srcData
== NULL
|| cnt
< 0)
3475 return WINED3DERR_INVALIDCALL
;
3477 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3478 for (i
= 0; i
< cnt
; i
++)
3479 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3481 for (i
= start
; i
< cnt
+ start
; ++i
) {
3482 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3485 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3490 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3491 IWineD3DDevice
*iface
,
3496 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3497 int cnt
= min(count
, MAX_CONST_B
- start
);
3499 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3500 iface
, dstData
, start
, count
);
3502 if (dstData
== NULL
|| cnt
< 0)
3503 return WINED3DERR_INVALIDCALL
;
3505 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3509 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3510 IWineD3DDevice
*iface
,
3515 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3516 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3518 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3519 iface
, srcData
, start
, count
);
3521 if (srcData
== NULL
|| cnt
< 0)
3522 return WINED3DERR_INVALIDCALL
;
3524 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3525 for (i
= 0; i
< cnt
; i
++)
3526 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3527 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3529 for (i
= start
; i
< cnt
+ start
; ++i
) {
3530 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3533 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3538 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3539 IWineD3DDevice
*iface
,
3544 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3545 int cnt
= min(count
, MAX_CONST_I
- start
);
3547 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3548 iface
, dstData
, start
, count
);
3550 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3551 return WINED3DERR_INVALIDCALL
;
3553 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3557 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3558 IWineD3DDevice
*iface
,
3560 CONST
float *srcData
,
3563 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3566 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3567 iface
, srcData
, start
, count
);
3569 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3570 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3571 return WINED3DERR_INVALIDCALL
;
3573 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3575 for (i
= 0; i
< count
; i
++)
3576 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3577 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3580 for (i
= start
; i
< count
+ start
; ++i
) {
3581 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3582 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3583 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3584 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3585 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3587 ptr
->idx
[ptr
->count
++] = i
;
3588 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3592 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3597 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3598 IWineD3DDevice
*iface
,
3600 CONST
float *srcData
,
3603 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3606 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3607 iface
, srcData
, start
, count
);
3609 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3610 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3611 return WINED3DERR_INVALIDCALL
;
3613 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3615 for (i
= 0; i
< count
; i
++)
3616 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3617 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3620 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3621 * context. On a context switch the old context will be fully dirtified
3623 memset(This
->activeContext
->vshader_const_dirty
+ start
, 1,
3624 sizeof(*This
->activeContext
->vshader_const_dirty
) * count
);
3625 This
->highest_dirty_vs_const
= max(This
->highest_dirty_vs_const
, start
+count
+1);
3627 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3632 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3633 IWineD3DDevice
*iface
,
3638 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3639 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3641 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3642 iface
, dstData
, start
, count
);
3644 if (dstData
== NULL
|| cnt
< 0)
3645 return WINED3DERR_INVALIDCALL
;
3647 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3651 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3653 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3654 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3658 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3659 int i
= This
->rev_tex_unit_map
[unit
];
3660 int j
= This
->texUnitMap
[stage
];
3662 This
->texUnitMap
[stage
] = unit
;
3663 if (i
!= -1 && i
!= stage
) {
3664 This
->texUnitMap
[i
] = -1;
3667 This
->rev_tex_unit_map
[unit
] = stage
;
3668 if (j
!= -1 && j
!= unit
) {
3669 This
->rev_tex_unit_map
[j
] = -1;
3673 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3676 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3677 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3678 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3679 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3680 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3681 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3682 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3683 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3684 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3686 if (color_op
== WINED3DTOP_DISABLE
) {
3687 /* Not used, and disable higher stages */
3688 while (i
< MAX_TEXTURES
) {
3689 This
->fixed_function_usage_map
[i
] = FALSE
;
3695 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3696 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3697 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3698 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3699 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3700 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3701 This
->fixed_function_usage_map
[i
] = TRUE
;
3703 This
->fixed_function_usage_map
[i
] = FALSE
;
3706 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3707 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3712 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3715 device_update_fixed_function_usage_map(This
);
3717 if (!GL_SUPPORT(NV_REGISTER_COMBINERS
) || This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3718 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3719 if (!This
->fixed_function_usage_map
[i
]) continue;
3721 if (This
->texUnitMap
[i
] != i
) {
3722 device_map_stage(This
, i
, i
);
3723 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3724 markTextureStagesDirty(This
, i
);
3730 /* Now work out the mapping */
3732 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3733 if (!This
->fixed_function_usage_map
[i
]) continue;
3735 if (This
->texUnitMap
[i
] != tex
) {
3736 device_map_stage(This
, i
, tex
);
3737 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3738 markTextureStagesDirty(This
, i
);
3745 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3746 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3749 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3750 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3751 device_map_stage(This
, i
, i
);
3752 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3753 if (i
< MAX_TEXTURES
) {
3754 markTextureStagesDirty(This
, i
);
3760 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3761 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3763 if (current_mapping
== -1) {
3764 /* Not currently used */
3768 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3769 /* Used by a fragment sampler */
3771 if (!pshader_sampler_tokens
) {
3772 /* No pixel shader, check fixed function */
3773 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3776 /* Pixel shader, check the shader's sampler map */
3777 return !pshader_sampler_tokens
[current_mapping
];
3780 /* Used by a vertex sampler */
3781 return !vshader_sampler_tokens
[current_mapping
];
3784 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3785 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3786 DWORD
*pshader_sampler_tokens
= NULL
;
3787 int start
= GL_LIMITS(combined_samplers
) - 1;
3791 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3793 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3794 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3795 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3798 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3799 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3800 if (vshader_sampler_tokens
[i
]) {
3801 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3802 /* Already mapped somewhere */
3806 while (start
>= 0) {
3807 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3808 device_map_stage(This
, vsampler_idx
, start
);
3809 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3821 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3822 BOOL vs
= use_vs(This
);
3823 BOOL ps
= use_ps(This
);
3826 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3827 * that would be really messy and require shader recompilation
3828 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3829 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3832 device_map_psamplers(This
);
3834 device_map_fixed_function_samplers(This
);
3838 device_map_vsamplers(This
, ps
);
3842 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3843 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3844 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3845 This
->updateStateBlock
->pixelShader
= pShader
;
3846 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3848 /* Handle recording of state blocks */
3849 if (This
->isRecordingState
) {
3850 TRACE("Recording... not performing anything\n");
3853 if (This
->isRecordingState
) {
3854 TRACE("Recording... not performing anything\n");
3855 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3856 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3860 if(pShader
== oldShader
) {
3861 TRACE("App is setting the old pixel shader over, nothing to do\n");
3865 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3866 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3868 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3869 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3874 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3875 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3877 if (NULL
== ppShader
) {
3878 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3879 return WINED3DERR_INVALIDCALL
;
3882 *ppShader
= This
->stateBlock
->pixelShader
;
3883 if (NULL
!= *ppShader
) {
3884 IWineD3DPixelShader_AddRef(*ppShader
);
3886 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3890 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3891 IWineD3DDevice
*iface
,
3893 CONST BOOL
*srcData
,
3896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3897 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3899 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3900 iface
, srcData
, start
, count
);
3902 if (srcData
== NULL
|| cnt
< 0)
3903 return WINED3DERR_INVALIDCALL
;
3905 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3906 for (i
= 0; i
< cnt
; i
++)
3907 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3909 for (i
= start
; i
< cnt
+ start
; ++i
) {
3910 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3913 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3918 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3919 IWineD3DDevice
*iface
,
3924 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3925 int cnt
= min(count
, MAX_CONST_B
- start
);
3927 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3928 iface
, dstData
, start
, count
);
3930 if (dstData
== NULL
|| cnt
< 0)
3931 return WINED3DERR_INVALIDCALL
;
3933 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3937 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3938 IWineD3DDevice
*iface
,
3943 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3944 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3946 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3947 iface
, srcData
, start
, count
);
3949 if (srcData
== NULL
|| cnt
< 0)
3950 return WINED3DERR_INVALIDCALL
;
3952 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3953 for (i
= 0; i
< cnt
; i
++)
3954 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3955 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3957 for (i
= start
; i
< cnt
+ start
; ++i
) {
3958 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3961 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3966 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3967 IWineD3DDevice
*iface
,
3972 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3973 int cnt
= min(count
, MAX_CONST_I
- start
);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface
, dstData
, start
, count
);
3978 if (dstData
== NULL
|| cnt
< 0)
3979 return WINED3DERR_INVALIDCALL
;
3981 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3985 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3986 IWineD3DDevice
*iface
,
3988 CONST
float *srcData
,
3991 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface
, srcData
, start
, count
);
3997 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3998 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3999 return WINED3DERR_INVALIDCALL
;
4001 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4003 for (i
= 0; i
< count
; i
++)
4004 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4005 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4008 for (i
= start
; i
< count
+ start
; ++i
) {
4009 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
4010 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
4011 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
4012 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
4013 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
4015 ptr
->idx
[ptr
->count
++] = i
;
4016 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
4020 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4025 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4026 IWineD3DDevice
*iface
,
4028 CONST
float *srcData
,
4031 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4035 iface
, srcData
, start
, count
);
4037 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4038 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4039 return WINED3DERR_INVALIDCALL
;
4041 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4043 for (i
= 0; i
< count
; i
++)
4044 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4045 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4048 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4049 * context. On a context switch the old context will be fully dirtified
4051 memset(This
->activeContext
->pshader_const_dirty
+ start
, 1,
4052 sizeof(*This
->activeContext
->pshader_const_dirty
) * count
);
4053 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, start
+count
+1);
4055 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4060 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
4061 IWineD3DDevice
*iface
,
4066 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4067 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
4069 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4070 iface
, dstData
, start
, count
);
4072 if (dstData
== NULL
|| cnt
< 0)
4073 return WINED3DERR_INVALIDCALL
;
4075 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4079 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4081 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
4082 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4084 DWORD DestFVF
= dest
->fvf
;
4086 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4090 if (lpStrideData
->u
.s
.normal
.lpData
) {
4091 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4094 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
4095 ERR("Source has no position mask\n");
4096 return WINED3DERR_INVALIDCALL
;
4099 /* We might access VBOs from this code, so hold the lock */
4102 if (dest
->resource
.allocatedMemory
== NULL
) {
4103 /* This may happen if we do direct locking into a vbo. Unlikely,
4104 * but theoretically possible(ddraw processvertices test)
4106 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4107 if(!dest
->resource
.allocatedMemory
) {
4109 ERR("Out of memory\n");
4110 return E_OUTOFMEMORY
;
4114 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4115 checkGLcall("glBindBufferARB");
4116 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4118 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4120 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4121 checkGLcall("glUnmapBufferARB");
4125 /* Get a pointer into the destination vbo(create one if none exists) and
4126 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4128 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
4129 dest
->Flags
|= VBFLAG_CREATEVBO
;
4130 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer
*) dest
);
4134 unsigned char extrabytes
= 0;
4135 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4136 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4137 * this may write 4 extra bytes beyond the area that should be written
4139 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4140 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4141 if(!dest_conv_addr
) {
4142 ERR("Out of memory\n");
4143 /* Continue without storing converted vertices */
4145 dest_conv
= dest_conv_addr
;
4149 * a) WINED3DRS_CLIPPING is enabled
4150 * b) WINED3DVOP_CLIP is passed
4152 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4153 static BOOL warned
= FALSE
;
4155 * The clipping code is not quite correct. Some things need
4156 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4157 * so disable clipping for now.
4158 * (The graphics in Half-Life are broken, and my processvertices
4159 * test crashes with IDirect3DDevice3)
4165 FIXME("Clipping is broken and disabled for now\n");
4167 } else doClip
= FALSE
;
4168 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4170 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4173 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4174 WINED3DTS_PROJECTION
,
4176 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4177 WINED3DTS_WORLDMATRIX(0),
4180 TRACE("View mat:\n");
4181 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
);
4182 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
);
4183 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
);
4184 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
);
4186 TRACE("Proj mat:\n");
4187 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
);
4188 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
);
4189 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
);
4190 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
);
4192 TRACE("World mat:\n");
4193 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
);
4194 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
);
4195 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
);
4196 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
);
4198 /* Get the viewport */
4199 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4200 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4201 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4203 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4204 multiply_matrix(&mat
,&proj_mat
,&mat
);
4206 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4208 for (i
= 0; i
< dwCount
; i
+= 1) {
4209 unsigned int tex_index
;
4211 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4212 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4213 /* The position first */
4215 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4217 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4219 /* Multiplication with world, view and projection matrix */
4220 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
);
4221 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
);
4222 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
);
4223 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
);
4225 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4227 /* WARNING: The following things are taken from d3d7 and were not yet checked
4228 * against d3d8 or d3d9!
4231 /* Clipping conditions: From msdn
4233 * A vertex is clipped if it does not match the following requirements
4237 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4239 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4240 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4245 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4246 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4249 /* "Normal" viewport transformation (not clipped)
4250 * 1) The values are divided by rhw
4251 * 2) The y axis is negative, so multiply it with -1
4252 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4253 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4254 * 4) Multiply x with Width/2 and add Width/2
4255 * 5) The same for the height
4256 * 6) Add the viewpoint X and Y to the 2D coordinates and
4257 * The minimum Z value to z
4258 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4260 * Well, basically it's simply a linear transformation into viewport
4272 z
*= vp
.MaxZ
- vp
.MinZ
;
4274 x
+= vp
.Width
/ 2 + vp
.X
;
4275 y
+= vp
.Height
/ 2 + vp
.Y
;
4280 /* That vertex got clipped
4281 * Contrary to OpenGL it is not dropped completely, it just
4282 * undergoes a different calculation.
4284 TRACE("Vertex got clipped\n");
4291 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4292 * outside of the main vertex buffer memory. That needs some more
4297 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4300 ( (float *) dest_ptr
)[0] = x
;
4301 ( (float *) dest_ptr
)[1] = y
;
4302 ( (float *) dest_ptr
)[2] = z
;
4303 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4305 dest_ptr
+= 3 * sizeof(float);
4307 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4308 dest_ptr
+= sizeof(float);
4313 ( (float *) dest_conv
)[0] = x
* w
;
4314 ( (float *) dest_conv
)[1] = y
* w
;
4315 ( (float *) dest_conv
)[2] = z
* w
;
4316 ( (float *) dest_conv
)[3] = w
;
4318 dest_conv
+= 3 * sizeof(float);
4320 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4321 dest_conv
+= sizeof(float);
4325 if (DestFVF
& WINED3DFVF_PSIZE
) {
4326 dest_ptr
+= sizeof(DWORD
);
4327 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4329 if (DestFVF
& WINED3DFVF_NORMAL
) {
4331 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4332 /* AFAIK this should go into the lighting information */
4333 FIXME("Didn't expect the destination to have a normal\n");
4334 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4336 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4340 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4342 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4344 static BOOL warned
= FALSE
;
4347 ERR("No diffuse color in source, but destination has one\n");
4351 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4352 dest_ptr
+= sizeof(DWORD
);
4355 *( (DWORD
*) dest_conv
) = 0xffffffff;
4356 dest_conv
+= sizeof(DWORD
);
4360 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4362 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4363 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4364 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4365 dest_conv
+= sizeof(DWORD
);
4370 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4371 /* What's the color value in the feedback buffer? */
4373 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4375 static BOOL warned
= FALSE
;
4378 ERR("No specular color in source, but destination has one\n");
4382 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4383 dest_ptr
+= sizeof(DWORD
);
4386 *( (DWORD
*) dest_conv
) = 0xFF000000;
4387 dest_conv
+= sizeof(DWORD
);
4391 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4393 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4394 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4395 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4396 dest_conv
+= sizeof(DWORD
);
4401 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4403 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4404 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4406 ERR("No source texture, but destination requests one\n");
4407 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4408 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4411 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4413 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4420 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4421 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4422 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4423 dwCount
* get_flexible_vertex_size(DestFVF
),
4425 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4426 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4433 #undef copy_and_next
4435 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4436 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4437 WineDirect3DVertexStridedData strided
;
4438 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4439 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4442 ERR("Output vertex declaration not implemented yet\n");
4445 /* Need any context to write to the vbo. */
4446 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4448 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4449 * control the streamIsUP flag, thus restore it afterwards.
4451 This
->stateBlock
->streamIsUP
= FALSE
;
4452 memset(&strided
, 0, sizeof(strided
));
4453 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4454 This
->stateBlock
->streamIsUP
= streamWasUP
;
4456 if(vbo
|| SrcStartIndex
) {
4458 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4459 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4461 * Also get the start index in, but only loop over all elements if there's something to add at all.
4463 #define FIXSRC(type) \
4464 if(strided.u.s.type.VBO) { \
4465 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4466 strided.u.s.type.VBO = 0; \
4467 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4469 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4473 if(strided.u.s.type.lpData) { \
4474 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4477 FIXSRC(blendWeights
);
4478 FIXSRC(blendMatrixIndices
);
4483 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4484 FIXSRC(texCoords
[i
]);
4497 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4501 * Get / Set Texture Stage States
4502 * TODO: Verify against dx9 definitions
4504 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4505 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4506 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4508 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4510 if (Stage
>= MAX_TEXTURES
) {
4511 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4515 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4516 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4518 if (This
->isRecordingState
) {
4519 TRACE("Recording... not performing anything\n");
4523 /* Checked after the assignments to allow proper stateblock recording */
4524 if(oldValue
== Value
) {
4525 TRACE("App is setting the old value over, nothing to do\n");
4529 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4530 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4531 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4532 * Changes in other states are important on disabled stages too
4537 if(Type
== WINED3DTSS_COLOROP
) {
4540 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4541 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4542 * they have to be disabled
4544 * The current stage is dirtified below.
4546 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4547 TRACE("Additionally dirtifying stage %d\n", i
);
4548 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4550 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4551 TRACE("New lowest disabled: %d\n", Stage
);
4552 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4553 /* Previously disabled stage enabled. Stages above it may need enabling
4554 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4555 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4557 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4560 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4561 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4564 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4565 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4567 This
->stateBlock
->lowest_disabled_stage
= i
;
4568 TRACE("New lowest disabled: %d\n", i
);
4570 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4571 /* TODO: Built a stage -> texture unit mapping for register combiners */
4575 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4580 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4581 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4582 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4583 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4590 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4591 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4592 IWineD3DBaseTexture
*oldTexture
;
4594 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4596 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4597 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4600 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4601 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4602 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4605 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4607 if(pTexture
!= NULL
) {
4608 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4610 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4611 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4612 return WINED3DERR_INVALIDCALL
;
4614 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4617 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4618 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4620 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4621 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4622 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4624 /* Handle recording of state blocks */
4625 if (This
->isRecordingState
) {
4626 TRACE("Recording... not performing anything\n");
4630 if(oldTexture
== pTexture
) {
4631 TRACE("App is setting the same texture again, nothing to do\n");
4635 /** NOTE: MSDN says that setTexture increases the reference count,
4636 * and that the application must set the texture back to null (or have a leaky application),
4637 * This means we should pass the refcount up to the parent
4638 *******************************/
4639 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4640 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4641 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4643 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4644 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4645 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4646 * so the COLOROP and ALPHAOP have to be dirtified.
4648 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4649 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4651 if(bindCount
== 1) {
4652 new->baseTexture
.sampler
= Stage
;
4654 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4658 if (NULL
!= oldTexture
) {
4659 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4660 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4662 IWineD3DBaseTexture_Release(oldTexture
);
4663 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4664 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4665 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4668 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4670 /* Have to do a search for the other sampler(s) where the texture is bound to
4671 * Shouldn't happen as long as apps bind a texture only to one stage
4673 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4674 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4675 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4676 old
->baseTexture
.sampler
= i
;
4683 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4688 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4689 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4691 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4693 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4694 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4697 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4698 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4699 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4702 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4704 IWineD3DBaseTexture_AddRef(*ppTexture
);
4706 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4714 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4715 IWineD3DSurface
**ppBackBuffer
) {
4716 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4717 IWineD3DSwapChain
*swapChain
;
4720 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4722 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4723 if (hr
== WINED3D_OK
) {
4724 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4725 IWineD3DSwapChain_Release(swapChain
);
4727 *ppBackBuffer
= NULL
;
4732 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4733 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4734 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4735 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4738 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4739 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4740 IWineD3DSwapChain
*swapChain
;
4743 if(iSwapChain
> 0) {
4744 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4745 if (hr
== WINED3D_OK
) {
4746 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4747 IWineD3DSwapChain_Release(swapChain
);
4749 FIXME("(%p) Error getting display mode\n", This
);
4752 /* Don't read the real display mode,
4753 but return the stored mode instead. X11 can't change the color
4754 depth, and some apps are pretty angry if they SetDisplayMode from
4755 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4757 Also don't relay to the swapchain because with ddraw it's possible
4758 that there isn't a swapchain at all */
4759 pMode
->Width
= This
->ddraw_width
;
4760 pMode
->Height
= This
->ddraw_height
;
4761 pMode
->Format
= This
->ddraw_format
;
4762 pMode
->RefreshRate
= 0;
4769 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4770 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4771 TRACE("(%p)->(%p)\n", This
, hWnd
);
4773 if(This
->ddraw_fullscreen
) {
4774 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4775 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4777 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4778 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4782 This
->ddraw_window
= hWnd
;
4786 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4787 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4788 TRACE("(%p)->(%p)\n", This
, hWnd
);
4790 *hWnd
= This
->ddraw_window
;
4795 * Stateblock related functions
4798 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4799 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4800 IWineD3DStateBlockImpl
*object
;
4801 HRESULT temp_result
;
4804 TRACE("(%p)\n", This
);
4806 if (This
->isRecordingState
) {
4807 return WINED3DERR_INVALIDCALL
;
4810 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4811 if (NULL
== object
) {
4812 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4813 return E_OUTOFMEMORY
;
4815 TRACE("(%p) created object %p\n", This
, object
);
4816 object
->wineD3DDevice
= This
;
4817 /** FIXME: object->parent = parent; **/
4818 object
->parent
= NULL
;
4819 object
->blockType
= WINED3DSBT_RECORDED
;
4821 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4823 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4824 list_init(&object
->lightMap
[i
]);
4827 temp_result
= allocate_shader_constants(object
);
4828 if (WINED3D_OK
!= temp_result
)
4831 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4832 This
->updateStateBlock
= object
;
4833 This
->isRecordingState
= TRUE
;
4835 TRACE("(%p) recording stateblock %p\n",This
, object
);
4839 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4840 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4842 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4844 if (!This
->isRecordingState
) {
4845 FIXME("(%p) not recording! returning error\n", This
);
4846 *ppStateBlock
= NULL
;
4847 return WINED3DERR_INVALIDCALL
;
4850 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4851 if(object
->changed
.renderState
[i
]) {
4852 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4853 object
->num_contained_render_states
++;
4856 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4857 if(object
->changed
.transform
[i
]) {
4858 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4859 object
->num_contained_transform_states
++;
4862 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4863 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4864 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4865 object
->num_contained_vs_consts_f
++;
4868 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4869 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4870 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4871 object
->num_contained_vs_consts_i
++;
4874 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4875 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4876 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4877 object
->num_contained_vs_consts_b
++;
4880 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4881 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4882 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4883 object
->num_contained_ps_consts_i
++;
4886 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4887 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4888 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4889 object
->num_contained_ps_consts_b
++;
4892 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4893 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4894 if(object
->changed
.textureState
[i
][j
]) {
4895 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4896 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4897 object
->num_contained_tss_states
++;
4901 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4902 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4903 if(object
->changed
.samplerState
[i
][j
]) {
4904 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4905 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4906 object
->num_contained_sampler_states
++;
4911 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4912 This
->isRecordingState
= FALSE
;
4913 This
->updateStateBlock
= This
->stateBlock
;
4914 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4915 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4916 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4921 * Scene related functions
4923 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4924 /* At the moment we have no need for any functionality at the beginning
4926 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4927 TRACE("(%p)\n", This
);
4930 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4931 return WINED3DERR_INVALIDCALL
;
4933 This
->inScene
= TRUE
;
4937 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4938 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4939 TRACE("(%p)\n", This
);
4941 if(!This
->inScene
) {
4942 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4943 return WINED3DERR_INVALIDCALL
;
4946 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4947 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4950 checkGLcall("glFlush");
4953 This
->inScene
= FALSE
;
4957 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4958 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4959 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4960 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4961 IWineD3DSwapChain
*swapChain
= NULL
;
4963 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4965 TRACE("(%p) Presenting the frame\n", This
);
4967 for(i
= 0 ; i
< swapchains
; i
++) {
4969 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4970 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4971 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4972 IWineD3DSwapChain_Release(swapChain
);
4978 /* Not called from the VTable (internal subroutine) */
4979 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4980 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4981 float Z
, DWORD Stencil
) {
4982 GLbitfield glMask
= 0;
4984 WINED3DRECT curRect
;
4986 WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4987 UINT drawable_width
, drawable_height
;
4988 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4990 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4991 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4992 * for the cleared parts, and the untouched parts.
4994 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4995 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4996 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4997 * checking all this if the dest surface is in the drawable anyway.
4999 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
5001 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
5002 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
5003 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5006 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5007 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5008 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
5009 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
5010 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5013 if(Count
> 0 && pRects
&& (
5014 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5015 pRects
[0].x2
< target
->currentDesc
.Width
||
5016 pRects
[0].y2
< target
->currentDesc
.Height
)) {
5017 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5024 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
5026 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
5029 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5030 apply_fbo_state((IWineD3DDevice
*) This
);
5033 /* Only set the values up once, as they are not changing */
5034 if (Flags
& WINED3DCLEAR_STENCIL
) {
5035 glClearStencil(Stencil
);
5036 checkGLcall("glClearStencil");
5037 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
5038 glStencilMask(0xFFFFFFFF);
5041 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5042 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5043 glDepthMask(GL_TRUE
);
5045 checkGLcall("glClearDepth");
5046 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
5047 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
5049 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
5050 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
5051 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5053 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5054 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5055 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
5056 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
5057 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5059 else if (Count
> 0 && pRects
&& (
5060 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5061 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
5062 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
5063 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5067 if (Flags
& WINED3DCLEAR_TARGET
) {
5068 TRACE("Clearing screen with glClear to color %x\n", Color
);
5069 glClearColor(D3DCOLOR_R(Color
),
5073 checkGLcall("glClearColor");
5075 /* Clear ALL colors! */
5076 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5077 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
5080 vp_rect
.left
= vp
->X
;
5081 vp_rect
.top
= vp
->Y
;
5082 vp_rect
.right
= vp
->X
+ vp
->Width
;
5083 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5084 if (!(Count
> 0 && pRects
)) {
5085 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5086 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5088 if(This
->render_offscreen
) {
5089 glScissor(vp_rect
.left
, vp_rect
.top
,
5090 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5092 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5093 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5095 checkGLcall("glScissor");
5097 checkGLcall("glClear");
5099 /* Now process each rect in turn */
5100 for (i
= 0; i
< Count
; i
++) {
5101 /* Note gl uses lower left, width/height */
5102 IntersectRect((RECT
*) &curRect
, &vp_rect
, (RECT
*) &pRects
[i
]);
5103 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5104 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5106 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5107 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5108 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5109 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5111 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5112 * The rectangle is not cleared, no error is returned, but further rectanlges are
5113 * still cleared if they are valid
5115 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5116 TRACE("Rectangle with negative dimensions, ignoring\n");
5120 if(This
->render_offscreen
) {
5121 glScissor(curRect
.x1
, curRect
.y1
,
5122 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5124 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5125 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5127 checkGLcall("glScissor");
5130 checkGLcall("glClear");
5134 /* Restore the old values (why..?) */
5135 if (Flags
& WINED3DCLEAR_STENCIL
) {
5136 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5138 if (Flags
& WINED3DCLEAR_TARGET
) {
5139 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5140 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5141 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5142 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5143 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5145 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5146 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5148 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5149 /* TODO: Move the fbo logic into ModifyLocation() */
5150 if(This
->render_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5151 target
->Flags
|= SFLAG_INTEXTURE
;
5154 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5155 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5156 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5157 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5165 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5166 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5167 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5168 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5170 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5171 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5173 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5174 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5175 /* TODO: What about depth stencil buffers without stencil bits? */
5176 return WINED3DERR_INVALIDCALL
;
5179 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5185 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
5186 UINT PrimitiveCount
) {
5188 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5190 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
5191 debug_d3dprimitivetype(PrimitiveType
),
5192 StartVertex
, PrimitiveCount
);
5194 if(!This
->stateBlock
->vertexDecl
) {
5195 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5196 return WINED3DERR_INVALIDCALL
;
5199 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5200 if(This
->stateBlock
->streamIsUP
) {
5201 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5202 This
->stateBlock
->streamIsUP
= FALSE
;
5205 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5206 This
->stateBlock
->loadBaseVertexIndex
= 0;
5207 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5209 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5210 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
5211 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5215 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5216 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5217 WINED3DPRIMITIVETYPE PrimitiveType
,
5218 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
5220 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5222 IWineD3DIndexBuffer
*pIB
;
5223 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
5226 pIB
= This
->stateBlock
->pIndexData
;
5228 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5229 * without an index buffer set. (The first time at least...)
5230 * D3D8 simply dies, but I doubt it can do much harm to return
5231 * D3DERR_INVALIDCALL there as well. */
5232 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5233 return WINED3DERR_INVALIDCALL
;
5236 if(!This
->stateBlock
->vertexDecl
) {
5237 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5238 return WINED3DERR_INVALIDCALL
;
5241 if(This
->stateBlock
->streamIsUP
) {
5242 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5243 This
->stateBlock
->streamIsUP
= FALSE
;
5245 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5247 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5248 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5249 minIndex
, NumVertices
, startIndex
, primCount
);
5251 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5252 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5258 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5259 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5260 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5263 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5264 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5269 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5270 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5271 UINT VertexStreamZeroStride
) {
5272 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5273 IWineD3DVertexBuffer
*vb
;
5275 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5276 debug_d3dprimitivetype(PrimitiveType
),
5277 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5279 if(!This
->stateBlock
->vertexDecl
) {
5280 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5281 return WINED3DERR_INVALIDCALL
;
5284 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5285 vb
= This
->stateBlock
->streamSource
[0];
5286 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5287 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5288 This
->stateBlock
->streamOffset
[0] = 0;
5289 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5290 This
->stateBlock
->streamIsUP
= TRUE
;
5291 This
->stateBlock
->loadBaseVertexIndex
= 0;
5293 /* TODO: Only mark dirty if drawing from a different UP address */
5294 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5296 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5297 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5299 /* MSDN specifies stream zero settings must be set to NULL */
5300 This
->stateBlock
->streamStride
[0] = 0;
5301 This
->stateBlock
->streamSource
[0] = NULL
;
5303 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5304 * the new stream sources or use UP drawing again
5309 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5310 UINT MinVertexIndex
, UINT NumVertices
,
5311 UINT PrimitiveCount
, CONST
void* pIndexData
,
5312 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5313 UINT VertexStreamZeroStride
) {
5315 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5316 IWineD3DVertexBuffer
*vb
;
5317 IWineD3DIndexBuffer
*ib
;
5319 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5320 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5321 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5322 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5324 if(!This
->stateBlock
->vertexDecl
) {
5325 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5326 return WINED3DERR_INVALIDCALL
;
5329 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5335 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5336 vb
= This
->stateBlock
->streamSource
[0];
5337 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5338 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5339 This
->stateBlock
->streamIsUP
= TRUE
;
5340 This
->stateBlock
->streamOffset
[0] = 0;
5341 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5343 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5344 This
->stateBlock
->baseVertexIndex
= 0;
5345 This
->stateBlock
->loadBaseVertexIndex
= 0;
5346 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5347 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5350 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5352 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5353 This
->stateBlock
->streamSource
[0] = NULL
;
5354 This
->stateBlock
->streamStride
[0] = 0;
5355 ib
= This
->stateBlock
->pIndexData
;
5357 IWineD3DIndexBuffer_Release(ib
);
5358 This
->stateBlock
->pIndexData
= NULL
;
5360 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5361 * SetStreamSource to specify a vertex buffer
5367 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5368 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5370 /* Mark the state dirty until we have nicer tracking
5371 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5374 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5375 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5376 This
->stateBlock
->baseVertexIndex
= 0;
5377 This
->up_strided
= DrawPrimStrideData
;
5378 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5379 This
->up_strided
= NULL
;
5383 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5384 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5385 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5387 /* Mark the state dirty until we have nicer tracking
5388 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5391 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5392 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5393 This
->stateBlock
->streamIsUP
= TRUE
;
5394 This
->stateBlock
->baseVertexIndex
= 0;
5395 This
->up_strided
= DrawPrimStrideData
;
5396 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5397 This
->up_strided
= NULL
;
5401 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5402 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5403 * not callable by the app directly no parameter validation checks are needed here.
5405 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5406 WINED3DLOCKED_BOX src
;
5407 WINED3DLOCKED_BOX dst
;
5409 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5411 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5412 * dirtification to improve loading performance.
5414 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5415 if(FAILED(hr
)) return hr
;
5416 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5418 IWineD3DVolume_UnlockBox(pSourceVolume
);
5422 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5424 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5426 IWineD3DVolume_UnlockBox(pSourceVolume
);
5428 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5433 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5434 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5435 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5436 HRESULT hr
= WINED3D_OK
;
5437 WINED3DRESOURCETYPE sourceType
;
5438 WINED3DRESOURCETYPE destinationType
;
5441 /* TODO: think about moving the code into IWineD3DBaseTexture */
5443 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5445 /* verify that the source and destination textures aren't NULL */
5446 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5447 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5448 This
, pSourceTexture
, pDestinationTexture
);
5449 hr
= WINED3DERR_INVALIDCALL
;
5452 if (pSourceTexture
== pDestinationTexture
) {
5453 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5454 This
, pSourceTexture
, pDestinationTexture
);
5455 hr
= WINED3DERR_INVALIDCALL
;
5457 /* Verify that the source and destination textures are the same type */
5458 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5459 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5461 if (sourceType
!= destinationType
) {
5462 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5464 hr
= WINED3DERR_INVALIDCALL
;
5467 /* check that both textures have the identical numbers of levels */
5468 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5469 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5470 hr
= WINED3DERR_INVALIDCALL
;
5473 if (WINED3D_OK
== hr
) {
5475 /* Make sure that the destination texture is loaded */
5476 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5478 /* Update every surface level of the texture */
5479 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5481 switch (sourceType
) {
5482 case WINED3DRTYPE_TEXTURE
:
5484 IWineD3DSurface
*srcSurface
;
5485 IWineD3DSurface
*destSurface
;
5487 for (i
= 0 ; i
< levels
; ++i
) {
5488 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5489 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5490 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5491 IWineD3DSurface_Release(srcSurface
);
5492 IWineD3DSurface_Release(destSurface
);
5493 if (WINED3D_OK
!= hr
) {
5494 WARN("(%p) : Call to update surface failed\n", This
);
5500 case WINED3DRTYPE_CUBETEXTURE
:
5502 IWineD3DSurface
*srcSurface
;
5503 IWineD3DSurface
*destSurface
;
5504 WINED3DCUBEMAP_FACES faceType
;
5506 for (i
= 0 ; i
< levels
; ++i
) {
5507 /* Update each cube face */
5508 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5509 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5510 if (WINED3D_OK
!= hr
) {
5511 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5513 TRACE("Got srcSurface %p\n", srcSurface
);
5515 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5516 if (WINED3D_OK
!= hr
) {
5517 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5519 TRACE("Got desrSurface %p\n", destSurface
);
5521 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5522 IWineD3DSurface_Release(srcSurface
);
5523 IWineD3DSurface_Release(destSurface
);
5524 if (WINED3D_OK
!= hr
) {
5525 WARN("(%p) : Call to update surface failed\n", This
);
5533 case WINED3DRTYPE_VOLUMETEXTURE
:
5535 IWineD3DVolume
*srcVolume
= NULL
;
5536 IWineD3DVolume
*destVolume
= NULL
;
5538 for (i
= 0 ; i
< levels
; ++i
) {
5539 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5540 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5541 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5542 IWineD3DVolume_Release(srcVolume
);
5543 IWineD3DVolume_Release(destVolume
);
5544 if (WINED3D_OK
!= hr
) {
5545 WARN("(%p) : Call to update volume failed\n", This
);
5553 FIXME("(%p) : Unsupported source and destination type\n", This
);
5554 hr
= WINED3DERR_INVALIDCALL
;
5561 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5562 IWineD3DSwapChain
*swapChain
;
5564 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5565 if(hr
== WINED3D_OK
) {
5566 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5567 IWineD3DSwapChain_Release(swapChain
);
5572 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5573 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5574 /* return a sensible default */
5576 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5577 FIXME("(%p) : stub\n", This
);
5581 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5585 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5586 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5587 if (texture
&& (texture
->resource
.format
== WINED3DFMT_P8
|| texture
->resource
.format
== WINED3DFMT_A8P8
)) {
5588 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5593 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5594 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5597 PALETTEENTRY
**palettes
;
5599 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5601 if (PaletteNumber
>= MAX_PALETTES
) {
5602 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5603 return WINED3DERR_INVALIDCALL
;
5606 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5607 NewSize
= This
->NumberOfPalettes
;
5610 } while(PaletteNumber
>= NewSize
);
5611 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5613 ERR("Out of memory!\n");
5614 return E_OUTOFMEMORY
;
5616 This
->palettes
= palettes
;
5617 This
->NumberOfPalettes
= NewSize
;
5620 if (!This
->palettes
[PaletteNumber
]) {
5621 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5622 if (!This
->palettes
[PaletteNumber
]) {
5623 ERR("Out of memory!\n");
5624 return E_OUTOFMEMORY
;
5628 for (j
= 0; j
< 256; ++j
) {
5629 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5630 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5631 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5632 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5634 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5635 TRACE("(%p) : returning\n", This
);
5639 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5640 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5642 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5643 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5644 /* What happens in such situation isn't documented; Native seems to silently abort
5645 on such conditions. Return Invalid Call. */
5646 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5647 return WINED3DERR_INVALIDCALL
;
5649 for (j
= 0; j
< 256; ++j
) {
5650 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5651 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5652 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5653 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5655 TRACE("(%p) : returning\n", This
);
5659 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5660 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5661 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5662 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5663 (tested with reference rasterizer). Return Invalid Call. */
5664 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5665 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5666 return WINED3DERR_INVALIDCALL
;
5668 /*TODO: stateblocks */
5669 if (This
->currentPalette
!= PaletteNumber
) {
5670 This
->currentPalette
= PaletteNumber
;
5671 dirtify_p8_texture_samplers(This
);
5673 TRACE("(%p) : returning\n", This
);
5677 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5678 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5679 if (PaletteNumber
== NULL
) {
5680 WARN("(%p) : returning Invalid Call\n", This
);
5681 return WINED3DERR_INVALIDCALL
;
5683 /*TODO: stateblocks */
5684 *PaletteNumber
= This
->currentPalette
;
5685 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5689 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5690 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5691 static BOOL showFixmes
= TRUE
;
5693 FIXME("(%p) : stub\n", This
);
5697 This
->softwareVertexProcessing
= bSoftware
;
5702 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5703 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5704 static BOOL showFixmes
= TRUE
;
5706 FIXME("(%p) : stub\n", This
);
5709 return This
->softwareVertexProcessing
;
5713 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5714 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5715 IWineD3DSwapChain
*swapChain
;
5718 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5720 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5721 if(hr
== WINED3D_OK
){
5722 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5723 IWineD3DSwapChain_Release(swapChain
);
5725 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5731 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5732 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5733 static BOOL showfixmes
= TRUE
;
5734 if(nSegments
!= 0.0f
) {
5736 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5743 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5744 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5745 static BOOL showfixmes
= TRUE
;
5747 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5753 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5754 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5755 /** TODO: remove casts to IWineD3DSurfaceImpl
5756 * NOTE: move code to surface to accomplish this
5757 ****************************************/
5758 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5759 int srcWidth
, srcHeight
;
5760 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5761 WINED3DFORMAT destFormat
, srcFormat
;
5763 int srcLeft
, destLeft
, destTop
;
5764 WINED3DPOOL srcPool
, destPool
;
5766 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5767 glDescriptor
*glDescription
= NULL
;
5771 CONVERT_TYPES convert
= NO_CONVERSION
;
5773 WINED3DSURFACE_DESC winedesc
;
5775 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5776 memset(&winedesc
, 0, sizeof(winedesc
));
5777 winedesc
.Width
= &srcSurfaceWidth
;
5778 winedesc
.Height
= &srcSurfaceHeight
;
5779 winedesc
.Pool
= &srcPool
;
5780 winedesc
.Format
= &srcFormat
;
5782 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5784 winedesc
.Width
= &destSurfaceWidth
;
5785 winedesc
.Height
= &destSurfaceHeight
;
5786 winedesc
.Pool
= &destPool
;
5787 winedesc
.Format
= &destFormat
;
5788 winedesc
.Size
= &destSize
;
5790 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5792 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5793 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5794 return WINED3DERR_INVALIDCALL
;
5797 /* This call loads the opengl surface directly, instead of copying the surface to the
5798 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5799 * copy in sysmem and use regular surface loading.
5801 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5802 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5803 if(convert
!= NO_CONVERSION
) {
5804 return IWineD3DSurface_BltFast(pDestinationSurface
,
5805 pDestPoint
? pDestPoint
->x
: 0,
5806 pDestPoint
? pDestPoint
->y
: 0,
5807 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5810 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5811 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5812 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5814 /* Get the update surface description */
5815 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5818 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5822 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5823 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5824 checkGLcall("glActiveTextureARB");
5827 /* Make sure the surface is loaded and up to date */
5828 IWineD3DSurface_PreLoad(pDestinationSurface
);
5830 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5832 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5833 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5834 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5835 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5836 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5837 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5840 /* This function doesn't support compressed textures
5841 the pitch is just bytesPerPixel * width */
5842 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5843 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5844 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5845 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5847 /* TODO DXT formats */
5849 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5850 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5852 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5854 ,glDescription
->level
5859 ,glDescription
->glFormat
5860 ,glDescription
->glType
5861 ,IWineD3DSurface_GetData(pSourceSurface
)
5865 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5867 /* need to lock the surface to get the data */
5868 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5871 /* TODO: Cube and volume support */
5873 /* not a whole row so we have to do it a line at a time */
5876 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5877 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5879 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5881 glTexSubImage2D(glDescription
->target
5882 ,glDescription
->level
5887 ,glDescription
->glFormat
5888 ,glDescription
->glType
5889 ,data
/* could be quicker using */
5894 } else { /* Full width, so just write out the whole texture */
5896 if (WINED3DFMT_DXT1
== destFormat
||
5897 WINED3DFMT_DXT2
== destFormat
||
5898 WINED3DFMT_DXT3
== destFormat
||
5899 WINED3DFMT_DXT4
== destFormat
||
5900 WINED3DFMT_DXT5
== destFormat
) {
5901 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5902 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5903 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5904 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5905 } if (destFormat
!= srcFormat
) {
5906 FIXME("Updating mixed format compressed texture is not curretly support\n");
5908 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5909 glDescription
->level
,
5910 glDescription
->glFormatInternal
,
5915 IWineD3DSurface_GetData(pSourceSurface
));
5918 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5923 glTexSubImage2D(glDescription
->target
5924 ,glDescription
->level
5929 ,glDescription
->glFormat
5930 ,glDescription
->glType
5931 ,IWineD3DSurface_GetData(pSourceSurface
)
5935 checkGLcall("glTexSubImage2D");
5939 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5940 sampler
= This
->rev_tex_unit_map
[0];
5941 if (sampler
!= -1) {
5942 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5948 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5949 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5950 struct WineD3DRectPatch
*patch
;
5954 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5956 if(!(Handle
|| pRectPatchInfo
)) {
5957 /* TODO: Write a test for the return value, thus the FIXME */
5958 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5959 return WINED3DERR_INVALIDCALL
;
5963 i
= PATCHMAP_HASHFUNC(Handle
);
5965 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5966 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5967 if(patch
->Handle
== Handle
) {
5974 TRACE("Patch does not exist. Creating a new one\n");
5975 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5976 patch
->Handle
= Handle
;
5977 list_add_head(&This
->patches
[i
], &patch
->entry
);
5979 TRACE("Found existing patch %p\n", patch
);
5982 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5983 * attributes we have to tesselate, read back, and draw. This needs a patch
5984 * management structure instance. Create one.
5986 * A possible improvement is to check if a vertex shader is used, and if not directly
5989 FIXME("Drawing an uncached patch. This is slow\n");
5990 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5993 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5994 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5995 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5997 TRACE("Tesselation density or patch info changed, retesselating\n");
5999 if(pRectPatchInfo
) {
6000 patch
->RectPatchInfo
= *pRectPatchInfo
;
6002 patch
->numSegs
[0] = pNumSegs
[0];
6003 patch
->numSegs
[1] = pNumSegs
[1];
6004 patch
->numSegs
[2] = pNumSegs
[2];
6005 patch
->numSegs
[3] = pNumSegs
[3];
6007 hr
= tesselate_rectpatch(This
, patch
);
6009 WARN("Patch tesselation failed\n");
6011 /* Do not release the handle to store the params of the patch */
6013 HeapFree(GetProcessHeap(), 0, patch
);
6019 This
->currentPatch
= patch
;
6020 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
6021 This
->currentPatch
= NULL
;
6023 /* Destroy uncached patches */
6025 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6026 HeapFree(GetProcessHeap(), 0, patch
);
6031 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
6032 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6033 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
6034 FIXME("(%p) : Stub\n", This
);
6038 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
6039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6041 struct WineD3DRectPatch
*patch
;
6043 TRACE("(%p) Handle(%d)\n", This
, Handle
);
6045 i
= PATCHMAP_HASHFUNC(Handle
);
6046 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6047 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6048 if(patch
->Handle
== Handle
) {
6049 TRACE("Deleting patch %p\n", patch
);
6050 list_remove(&patch
->entry
);
6051 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6052 HeapFree(GetProcessHeap(), 0, patch
);
6057 /* TODO: Write a test for the return value */
6058 FIXME("Attempt to destroy nonexistent patch\n");
6059 return WINED3DERR_INVALIDCALL
;
6062 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6064 IWineD3DSwapChain
*swapchain
;
6066 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6067 if (SUCCEEDED(hr
)) {
6068 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6075 void bind_fbo(IWineD3DDevice
*iface
, GLenum target
, GLuint
*fbo
) {
6076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6079 GL_EXTCALL(glGenFramebuffersEXT(1, fbo
));
6080 checkGLcall("glGenFramebuffersEXT()");
6082 GL_EXTCALL(glBindFramebufferEXT(target
, *fbo
));
6083 checkGLcall("glBindFramebuffer()");
6086 /* TODO: Handle stencil attachments */
6087 void attach_depth_stencil_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, IWineD3DSurface
*depth_stencil
, BOOL use_render_buffer
) {
6088 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
6090 if (use_render_buffer
&& depth_stencil_impl
->current_renderbuffer
) {
6091 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, depth_stencil_impl
->current_renderbuffer
->id
));
6092 checkGLcall("glFramebufferRenderbufferEXT()");
6094 IWineD3DBaseTextureImpl
*texture_impl
;
6095 GLenum texttarget
, target
;
6096 GLint old_binding
= 0;
6098 texttarget
= depth_stencil_impl
->glDescription
.target
;
6099 if(texttarget
== GL_TEXTURE_2D
) {
6100 target
= GL_TEXTURE_2D
;
6101 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
6102 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
6103 target
= GL_TEXTURE_RECTANGLE_ARB
;
6104 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
6106 target
= GL_TEXTURE_CUBE_MAP_ARB
;
6107 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6110 IWineD3DSurface_PreLoad(depth_stencil
);
6112 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6113 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6114 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
6115 glBindTexture(target
, old_binding
);
6117 /* Update base texture states array */
6118 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6119 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6120 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6121 if (texture_impl
->baseTexture
.bindCount
) {
6122 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6125 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6128 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
,
6129 depth_stencil_impl
->glDescription
.textureName
, depth_stencil_impl
->glDescription
.level
));
6130 checkGLcall("glFramebufferTexture2DEXT()");
6134 static void attach_surface_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, DWORD idx
, IWineD3DSurface
*surface
) {
6135 const IWineD3DSurfaceImpl
*surface_impl
= (IWineD3DSurfaceImpl
*)surface
;
6136 IWineD3DBaseTextureImpl
*texture_impl
;
6137 GLenum texttarget
, target
;
6140 texttarget
= surface_impl
->glDescription
.target
;
6141 if(texttarget
== GL_TEXTURE_2D
) {
6142 target
= GL_TEXTURE_2D
;
6143 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
6144 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
6145 target
= GL_TEXTURE_RECTANGLE_ARB
;
6146 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
6148 target
= GL_TEXTURE_CUBE_MAP_ARB
;
6149 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6152 IWineD3DSurface_PreLoad(surface
);
6154 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6155 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6156 glBindTexture(target
, old_binding
);
6158 /* Update base texture states array */
6159 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6160 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6161 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6162 if (texture_impl
->baseTexture
.bindCount
) {
6163 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6166 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6169 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
,
6170 surface_impl
->glDescription
.textureName
, surface_impl
->glDescription
.level
));
6172 checkGLcall("attach_surface_fbo");
6175 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
6176 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6177 IWineD3DSwapChain
*swapchain
;
6179 swapchain
= get_swapchain(surface
);
6183 TRACE("Surface %p is onscreen\n", surface
);
6185 ActivateContext(This
, surface
, CTXUSAGE_CLEAR
);
6187 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6188 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6189 glDrawBuffer(buffer
);
6190 checkGLcall("glDrawBuffer()");
6192 TRACE("Surface %p is offscreen\n", surface
);
6194 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_CLEAR
);
6196 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6197 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6198 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6199 checkGLcall("glFramebufferRenderbufferEXT");
6203 glEnable(GL_SCISSOR_TEST
);
6205 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6207 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6208 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6210 checkGLcall("glScissor");
6212 glDisable(GL_SCISSOR_TEST
);
6215 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6216 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6218 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
6219 glClear(GL_COLOR_BUFFER_BIT
);
6220 checkGLcall("glClear");
6222 if (This
->render_offscreen
) {
6223 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6225 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6226 checkGLcall("glBindFramebuffer()");
6229 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6230 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6231 glDrawBuffer(GL_BACK
);
6232 checkGLcall("glDrawBuffer()");
6238 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6239 unsigned int r
, g
, b
, a
;
6242 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6243 destfmt
== WINED3DFMT_R8G8B8
)
6246 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6248 a
= (color
& 0xff000000) >> 24;
6249 r
= (color
& 0x00ff0000) >> 16;
6250 g
= (color
& 0x0000ff00) >> 8;
6251 b
= (color
& 0x000000ff) >> 0;
6255 case WINED3DFMT_R5G6B5
:
6256 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6263 TRACE("Returning %08x\n", ret
);
6266 case WINED3DFMT_X1R5G5B5
:
6267 case WINED3DFMT_A1R5G5B5
:
6276 TRACE("Returning %08x\n", ret
);
6280 TRACE("Returning %08x\n", a
);
6283 case WINED3DFMT_X4R4G4B4
:
6284 case WINED3DFMT_A4R4G4B4
:
6293 TRACE("Returning %08x\n", ret
);
6296 case WINED3DFMT_R3G3B2
:
6303 TRACE("Returning %08x\n", ret
);
6306 case WINED3DFMT_X8B8G8R8
:
6307 case WINED3DFMT_A8B8G8R8
:
6312 TRACE("Returning %08x\n", ret
);
6315 case WINED3DFMT_A2R10G10B10
:
6317 r
= (r
* 1024) / 256;
6318 g
= (g
* 1024) / 256;
6319 b
= (b
* 1024) / 256;
6324 TRACE("Returning %08x\n", ret
);
6327 case WINED3DFMT_A2B10G10R10
:
6329 r
= (r
* 1024) / 256;
6330 g
= (g
* 1024) / 256;
6331 b
= (b
* 1024) / 256;
6336 TRACE("Returning %08x\n", ret
);
6340 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6345 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6346 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6347 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6349 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6351 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6352 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6353 return WINED3DERR_INVALIDCALL
;
6356 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6357 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6360 /* Just forward this to the DirectDraw blitting engine */
6361 memset(&BltFx
, 0, sizeof(BltFx
));
6362 BltFx
.dwSize
= sizeof(BltFx
);
6363 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6364 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6368 /* rendertarget and depth stencil functions */
6369 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6370 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6372 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6373 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6374 return WINED3DERR_INVALIDCALL
;
6377 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6378 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6379 /* Note inc ref on returned surface */
6380 if(*ppRenderTarget
!= NULL
)
6381 IWineD3DSurface_AddRef(*ppRenderTarget
);
6385 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6386 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6387 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6388 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6389 IWineD3DSwapChainImpl
*Swapchain
;
6392 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6394 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6395 if(hr
!= WINED3D_OK
) {
6396 ERR("Can't get the swapchain\n");
6400 /* Make sure to release the swapchain */
6401 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6403 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6404 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6405 return WINED3DERR_INVALIDCALL
;
6407 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6408 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6409 return WINED3DERR_INVALIDCALL
;
6412 if(Swapchain
->frontBuffer
!= Front
) {
6413 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6415 if(Swapchain
->frontBuffer
)
6416 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6417 Swapchain
->frontBuffer
= Front
;
6419 if(Swapchain
->frontBuffer
) {
6420 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6424 if(Back
&& !Swapchain
->backBuffer
) {
6425 /* We need memory for the back buffer array - only one back buffer this way */
6426 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6427 if(!Swapchain
->backBuffer
) {
6428 ERR("Out of memory\n");
6429 return E_OUTOFMEMORY
;
6433 if(Swapchain
->backBuffer
[0] != Back
) {
6434 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6436 /* What to do about the context here in the case of multithreading? Not sure.
6437 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6440 if(!Swapchain
->backBuffer
[0]) {
6441 /* GL was told to draw to the front buffer at creation,
6444 glDrawBuffer(GL_BACK
);
6445 checkGLcall("glDrawBuffer(GL_BACK)");
6446 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6447 Swapchain
->presentParms
.BackBufferCount
= 1;
6449 /* That makes problems - disable for now */
6450 /* glDrawBuffer(GL_FRONT); */
6451 checkGLcall("glDrawBuffer(GL_FRONT)");
6452 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6453 Swapchain
->presentParms
.BackBufferCount
= 0;
6457 if(Swapchain
->backBuffer
[0])
6458 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6459 Swapchain
->backBuffer
[0] = Back
;
6461 if(Swapchain
->backBuffer
[0]) {
6462 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6464 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6465 Swapchain
->backBuffer
= NULL
;
6473 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6474 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6475 *ppZStencilSurface
= This
->stencilBufferTarget
;
6476 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6478 if(*ppZStencilSurface
!= NULL
) {
6479 /* Note inc ref on returned surface */
6480 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6483 return WINED3DERR_NOTFOUND
;
6487 /* TODO: Handle stencil attachments */
6488 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
6489 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6491 TRACE("Set depth stencil to %p\n", depth_stencil
);
6493 if (depth_stencil
) {
6494 attach_depth_stencil_fbo(This
, GL_FRAMEBUFFER_EXT
, depth_stencil
, TRUE
);
6496 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
6497 checkGLcall("glFramebufferTexture2DEXT()");
6501 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
6502 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6504 TRACE("Set render target %u to %p\n", idx
, render_target
);
6506 if (render_target
) {
6507 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, idx
, render_target
);
6508 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
6510 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
6511 checkGLcall("glFramebufferTexture2DEXT()");
6513 This
->draw_buffers
[idx
] = GL_NONE
;
6517 static void check_fbo_status(IWineD3DDevice
*iface
) {
6518 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6521 status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
6522 if (status
== GL_FRAMEBUFFER_COMPLETE_EXT
) {
6523 TRACE("FBO complete\n");
6525 IWineD3DSurfaceImpl
*attachment
;
6527 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status
), status
);
6529 /* Dump the FBO attachments */
6530 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6531 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_color_attachments
[i
];
6533 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i
, attachment
, debug_d3dformat(attachment
->resource
.format
),
6534 attachment
->pow2Width
, attachment
->pow2Height
);
6537 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_depth_attachment
;
6539 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment
, debug_d3dformat(attachment
->resource
.format
),
6540 attachment
->pow2Width
, attachment
->pow2Height
);
6545 static BOOL
depth_mismatch_fbo(IWineD3DDevice
*iface
) {
6546 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6547 IWineD3DSurfaceImpl
*rt_impl
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
6548 IWineD3DSurfaceImpl
*ds_impl
= (IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
;
6550 if (!ds_impl
) return FALSE
;
6552 if (ds_impl
->current_renderbuffer
) {
6553 return (rt_impl
->pow2Width
!= ds_impl
->current_renderbuffer
->width
||
6554 rt_impl
->pow2Height
!= ds_impl
->current_renderbuffer
->height
);
6557 return (rt_impl
->pow2Width
!= ds_impl
->pow2Width
||
6558 rt_impl
->pow2Height
!= ds_impl
->pow2Height
);
6561 void apply_fbo_state(IWineD3DDevice
*iface
) {
6562 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6565 if (This
->render_offscreen
) {
6566 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6568 /* Apply render targets */
6569 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6570 IWineD3DSurface
*render_target
= This
->render_targets
[i
];
6571 if (This
->fbo_color_attachments
[i
] != render_target
) {
6572 set_render_target_fbo(iface
, i
, render_target
);
6573 This
->fbo_color_attachments
[i
] = render_target
;
6577 /* Apply depth targets */
6578 if (This
->fbo_depth_attachment
!= This
->stencilBufferTarget
|| depth_mismatch_fbo(iface
)) {
6579 unsigned int w
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Width
;
6580 unsigned int h
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Height
;
6582 if (This
->stencilBufferTarget
) {
6583 surface_set_compatible_renderbuffer(This
->stencilBufferTarget
, w
, h
);
6585 set_depth_stencil_fbo(iface
, This
->stencilBufferTarget
);
6586 This
->fbo_depth_attachment
= This
->stencilBufferTarget
;
6589 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
6590 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
6591 checkGLcall("glDrawBuffers()");
6593 glDrawBuffer(This
->draw_buffers
[0]);
6594 checkGLcall("glDrawBuffer()");
6597 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6600 check_fbo_status(iface
);
6603 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6604 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6605 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6606 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6607 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6609 POINT offset
= {0, 0};
6611 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6612 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6613 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6614 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6617 case WINED3DTEXF_LINEAR
:
6618 gl_filter
= GL_LINEAR
;
6622 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6623 case WINED3DTEXF_NONE
:
6624 case WINED3DTEXF_POINT
:
6625 gl_filter
= GL_NEAREST
;
6629 /* Attach src surface to src fbo */
6630 src_swapchain
= get_swapchain(src_surface
);
6631 if (src_swapchain
) {
6632 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6634 TRACE("Source surface %p is onscreen\n", src_surface
);
6635 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6636 /* Make sure the drawable is up to date. In the offscreen case
6637 * attach_surface_fbo() implicitly takes care of this. */
6638 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6640 if(buffer
== GL_FRONT
) {
6643 ClientToScreen(This
->ddraw_window
, &offset
);
6644 GetClientRect(This
->ddraw_window
, &windowsize
);
6645 h
= windowsize
.bottom
- windowsize
.top
;
6646 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6647 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6648 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6650 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6651 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6655 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6656 glReadBuffer(buffer
);
6657 checkGLcall("glReadBuffer()");
6659 TRACE("Source surface %p is offscreen\n", src_surface
);
6661 bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->src_fbo
);
6662 attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6663 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6664 checkGLcall("glReadBuffer()");
6665 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6666 checkGLcall("glFramebufferRenderbufferEXT");
6670 /* Attach dst surface to dst fbo */
6671 dst_swapchain
= get_swapchain(dst_surface
);
6672 if (dst_swapchain
) {
6673 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6675 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6676 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6677 /* Make sure the drawable is up to date. In the offscreen case
6678 * attach_surface_fbo() implicitly takes care of this. */
6679 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6681 if(buffer
== GL_FRONT
) {
6684 ClientToScreen(This
->ddraw_window
, &offset
);
6685 GetClientRect(This
->ddraw_window
, &windowsize
);
6686 h
= windowsize
.bottom
- windowsize
.top
;
6687 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6688 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6689 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6691 /* Screen coords = window coords, surface height = window height */
6692 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6693 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6697 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6698 glDrawBuffer(buffer
);
6699 checkGLcall("glDrawBuffer()");
6701 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6703 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6704 if(!src_swapchain
) {
6705 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6709 bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6710 attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6711 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6712 checkGLcall("glDrawBuffer()");
6713 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6714 checkGLcall("glFramebufferRenderbufferEXT");
6716 glDisable(GL_SCISSOR_TEST
);
6717 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6720 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6721 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6722 checkGLcall("glBlitFramebuffer()");
6724 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6725 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6726 checkGLcall("glBlitFramebuffer()");
6729 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6731 if (This
->render_offscreen
) {
6732 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6734 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6735 checkGLcall("glBindFramebuffer()");
6738 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6739 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6740 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6741 glDrawBuffer(GL_BACK
);
6742 checkGLcall("glDrawBuffer()");
6747 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6748 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6749 WINED3DVIEWPORT viewport
;
6751 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6753 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6754 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6755 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6756 return WINED3DERR_INVALIDCALL
;
6759 /* MSDN says that null disables the render target
6760 but a device must always be associated with a render target
6761 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6763 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6764 FIXME("Trying to set render target 0 to NULL\n");
6765 return WINED3DERR_INVALIDCALL
;
6767 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6768 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
);
6769 return WINED3DERR_INVALIDCALL
;
6772 /* If we are trying to set what we already have, don't bother */
6773 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6774 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6777 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6778 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6779 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6781 /* Render target 0 is special */
6782 if(RenderTargetIndex
== 0) {
6783 /* Finally, reset the viewport as the MSDN states. */
6784 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6785 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6788 viewport
.MaxZ
= 1.0f
;
6789 viewport
.MinZ
= 0.0f
;
6790 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6791 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6792 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6794 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6799 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6800 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6801 HRESULT hr
= WINED3D_OK
;
6802 IWineD3DSurface
*tmp
;
6804 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6806 if (pNewZStencil
== This
->stencilBufferTarget
) {
6807 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6809 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6810 * depending on the renter target implementation being used.
6811 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6812 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6813 * stencil buffer and incur an extra memory overhead
6814 ******************************************************/
6816 if (This
->stencilBufferTarget
) {
6817 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6818 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6819 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6822 tmp
= This
->stencilBufferTarget
;
6823 This
->stencilBufferTarget
= pNewZStencil
;
6824 /* should we be calling the parent or the wined3d surface? */
6825 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6826 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6829 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6830 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6831 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6832 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6833 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6840 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6841 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6842 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6843 /* TODO: the use of Impl is deprecated. */
6844 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6845 WINED3DLOCKED_RECT lockedRect
;
6847 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6849 /* some basic validation checks */
6850 if(This
->cursorTexture
) {
6851 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6853 glDeleteTextures(1, &This
->cursorTexture
);
6855 This
->cursorTexture
= 0;
6858 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6859 This
->haveHardwareCursor
= TRUE
;
6861 This
->haveHardwareCursor
= FALSE
;
6864 WINED3DLOCKED_RECT rect
;
6866 /* MSDN: Cursor must be A8R8G8B8 */
6867 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6868 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6869 return WINED3DERR_INVALIDCALL
;
6872 /* MSDN: Cursor must be smaller than the display mode */
6873 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6874 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6875 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
);
6876 return WINED3DERR_INVALIDCALL
;
6879 if (!This
->haveHardwareCursor
) {
6880 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6882 /* Do not store the surface's pointer because the application may
6883 * release it after setting the cursor image. Windows doesn't
6884 * addref the set surface, so we can't do this either without
6885 * creating circular refcount dependencies. Copy out the gl texture
6888 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6889 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6890 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6892 const GlPixelFormatDesc
*glDesc
;
6893 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6894 char *mem
, *bits
= (char *)rect
.pBits
;
6895 GLint intfmt
= glDesc
->glInternal
;
6896 GLint format
= glDesc
->glFormat
;
6897 GLint type
= glDesc
->glType
;
6898 INT height
= This
->cursorHeight
;
6899 INT width
= This
->cursorWidth
;
6900 INT bpp
= tableEntry
->bpp
;
6903 /* Reformat the texture memory (pitch and width can be
6905 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6906 for(i
= 0; i
< height
; i
++)
6907 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6908 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6911 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6912 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6913 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6916 /* Make sure that a proper texture unit is selected */
6917 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6918 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6919 checkGLcall("glActiveTextureARB");
6921 sampler
= This
->rev_tex_unit_map
[0];
6922 if (sampler
!= -1) {
6923 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6925 /* Create a new cursor texture */
6926 glGenTextures(1, &This
->cursorTexture
);
6927 checkGLcall("glGenTextures");
6928 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6929 checkGLcall("glBindTexture");
6930 /* Copy the bitmap memory into the cursor texture */
6931 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6932 HeapFree(GetProcessHeap(), 0, mem
);
6933 checkGLcall("glTexImage2D");
6935 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6936 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6937 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6944 FIXME("A cursor texture was not returned.\n");
6945 This
->cursorTexture
= 0;
6950 /* Draw a hardware cursor */
6951 ICONINFO cursorInfo
;
6953 /* Create and clear maskBits because it is not needed for
6954 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6956 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6957 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6958 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6959 WINED3DLOCK_NO_DIRTY_UPDATE
|
6960 WINED3DLOCK_READONLY
6962 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6963 pSur
->currentDesc
.Height
);
6965 cursorInfo
.fIcon
= FALSE
;
6966 cursorInfo
.xHotspot
= XHotSpot
;
6967 cursorInfo
.yHotspot
= YHotSpot
;
6968 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6969 pSur
->currentDesc
.Height
, 1,
6971 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6972 pSur
->currentDesc
.Height
, 1,
6973 32, lockedRect
.pBits
);
6974 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6975 /* Create our cursor and clean up. */
6976 cursor
= CreateIconIndirect(&cursorInfo
);
6978 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6979 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6980 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6981 This
->hardwareCursor
= cursor
;
6982 HeapFree(GetProcessHeap(), 0, maskBits
);
6986 This
->xHotSpot
= XHotSpot
;
6987 This
->yHotSpot
= YHotSpot
;
6991 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6992 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6993 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6995 This
->xScreenSpace
= XScreenSpace
;
6996 This
->yScreenSpace
= YScreenSpace
;
7002 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
7003 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7004 BOOL oldVisible
= This
->bCursorVisible
;
7007 TRACE("(%p) : visible(%d)\n", This
, bShow
);
7010 * When ShowCursor is first called it should make the cursor appear at the OS's last
7011 * known cursor position. Because of this, some applications just repetitively call
7012 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7015 This
->xScreenSpace
= pt
.x
;
7016 This
->yScreenSpace
= pt
.y
;
7018 if (This
->haveHardwareCursor
) {
7019 This
->bCursorVisible
= bShow
;
7021 SetCursor(This
->hardwareCursor
);
7027 if (This
->cursorTexture
)
7028 This
->bCursorVisible
= bShow
;
7034 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
7035 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7036 IWineD3DResourceImpl
*resource
;
7037 TRACE("(%p) : state (%u)\n", This
, This
->state
);
7039 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7040 switch (This
->state
) {
7043 case WINED3DERR_DEVICELOST
:
7045 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7046 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
7047 return WINED3DERR_DEVICENOTRESET
;
7049 return WINED3DERR_DEVICELOST
;
7051 case WINED3DERR_DRIVERINTERNALERROR
:
7052 return WINED3DERR_DRIVERINTERNALERROR
;
7056 return WINED3DERR_DRIVERINTERNALERROR
;
7060 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
7061 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7062 /** FIXME: Resource tracking needs to be done,
7063 * The closes we can do to this is set the priorities of all managed textures low
7064 * and then reset them.
7065 ***********************************************************/
7066 FIXME("(%p) : stub\n", This
);
7070 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7071 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
7073 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7074 if(surface
->Flags
& SFLAG_DIBSECTION
) {
7075 /* Release the DC */
7076 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
7077 DeleteDC(surface
->hDC
);
7078 /* Release the DIB section */
7079 DeleteObject(surface
->dib
.DIBsection
);
7080 surface
->dib
.bitmap_data
= NULL
;
7081 surface
->resource
.allocatedMemory
= NULL
;
7082 surface
->Flags
&= ~SFLAG_DIBSECTION
;
7084 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
7085 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
7086 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
7087 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
7088 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
7089 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
7091 surface
->pow2Width
= surface
->pow2Height
= 1;
7092 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
7093 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
7095 surface
->glRect
.left
= 0;
7096 surface
->glRect
.top
= 0;
7097 surface
->glRect
.right
= surface
->pow2Width
;
7098 surface
->glRect
.bottom
= surface
->pow2Height
;
7100 if(surface
->glDescription
.textureName
) {
7101 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
7103 glDeleteTextures(1, &surface
->glDescription
.textureName
);
7105 surface
->glDescription
.textureName
= 0;
7106 surface
->Flags
&= ~SFLAG_CLIENT
;
7108 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
7109 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
7110 surface
->Flags
|= SFLAG_NONPOW2
;
7112 surface
->Flags
&= ~SFLAG_NONPOW2
;
7114 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
7115 surface
->resource
.allocatedMemory
= NULL
;
7116 surface
->resource
.heapMemory
= NULL
;
7117 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
7118 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7119 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
7120 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
7122 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
7126 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
7127 TRACE("Unloading resource %p\n", resource
);
7128 IWineD3DResource_UnLoad(resource
);
7129 IWineD3DResource_Release(resource
);
7133 static void reset_fbo_state(IWineD3DDevice
*iface
) {
7134 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7138 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
7139 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7142 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
7145 if (This
->src_fbo
) {
7146 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->src_fbo
));
7149 if (This
->dst_fbo
) {
7150 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->dst_fbo
));
7153 checkGLcall("Tear down FBOs\n");
7156 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7157 This
->fbo_color_attachments
[i
] = NULL
;
7159 This
->fbo_depth_attachment
= NULL
;
7162 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, WINED3DPRESENT_PARAMETERS
*pp
) {
7164 WINED3DDISPLAYMODE m
;
7167 /* All Windowed modes are supported, as is leaving the current mode */
7168 if(pp
->Windowed
) return TRUE
;
7169 if(!pp
->BackBufferWidth
) return TRUE
;
7170 if(!pp
->BackBufferHeight
) return TRUE
;
7172 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
7173 for(i
= 0; i
< count
; i
++) {
7174 memset(&m
, 0, sizeof(m
));
7175 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
7177 ERR("EnumAdapterModes failed\n");
7179 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
7180 /* Mode found, it is supported */
7184 /* Mode not found -> not supported */
7188 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7189 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7190 IWineD3DSwapChainImpl
*swapchain
;
7192 BOOL DisplayModeChanged
= FALSE
;
7193 WINED3DDISPLAYMODE mode
;
7194 IWineD3DBaseShaderImpl
*shader
;
7195 IWineD3DSurfaceImpl
*target
;
7197 TRACE("(%p)\n", This
);
7199 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7201 ERR("Failed to get the first implicit swapchain\n");
7205 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7206 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7207 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7208 pPresentationParameters
->BackBufferHeight
);
7209 return WINED3DERR_INVALIDCALL
;
7212 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7213 * on an existing gl context, so there's no real need for recreation.
7215 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7217 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7219 TRACE("New params:\n");
7220 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7221 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7222 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7223 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7224 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7225 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7226 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7227 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7228 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7229 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7230 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7231 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7232 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7234 /* No special treatment of these parameters. Just store them */
7235 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7236 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7237 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7238 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7240 /* What to do about these? */
7241 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7242 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7243 ERR("Cannot change the back buffer count yet\n");
7245 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7246 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7247 ERR("Cannot change the back buffer format yet\n");
7249 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7250 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7251 ERR("Cannot change the device window yet\n");
7253 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
7254 ERR("What do do about a changed auto depth stencil parameter?\n");
7257 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
7258 reset_fbo_state((IWineD3DDevice
*) This
);
7261 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
7262 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
7263 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
7267 if(This
->depth_blt_texture
) {
7268 glDeleteTextures(1, &This
->depth_blt_texture
);
7269 This
->depth_blt_texture
= 0;
7271 if (This
->depth_blt_rb
) {
7272 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
7273 This
->depth_blt_rb
= 0;
7274 This
->depth_blt_rb_w
= 0;
7275 This
->depth_blt_rb_h
= 0;
7277 This
->frag_pipe
->free_private(iface
);
7278 This
->shader_backend
->shader_free_private(iface
);
7280 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
7281 /* Textures are recreated below */
7282 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
7283 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7284 This
->dummyTextureName
[i
] = 0;
7288 while(This
->numContexts
) {
7289 DestroyContext(This
, This
->contexts
[0]);
7291 This
->activeContext
= NULL
;
7292 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
7293 swapchain
->context
= NULL
;
7294 swapchain
->num_contexts
= 0;
7296 if(pPresentationParameters
->Windowed
) {
7297 mode
.Width
= swapchain
->orig_width
;
7298 mode
.Height
= swapchain
->orig_height
;
7299 mode
.RefreshRate
= 0;
7300 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7302 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7303 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7304 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7305 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7308 /* Should Width == 800 && Height == 0 set 800x600? */
7309 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7310 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7311 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7318 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
7319 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
7323 if(!pPresentationParameters
->Windowed
) {
7324 DisplayModeChanged
= TRUE
;
7326 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7327 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7329 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7330 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7331 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7333 if(This
->auto_depth_stencil_buffer
) {
7334 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7338 /* Now set the new viewport */
7339 IWineD3DDevice_SetViewport(iface
, &vp
);
7342 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7343 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7344 DisplayModeChanged
) {
7346 IWineD3DDevice_SetFullscreen(iface
, !pPresentationParameters
->Windowed
);
7347 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7348 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7349 } else if(!pPresentationParameters
->Windowed
) {
7350 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7351 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7352 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7353 * Reset to clear up their mess. Guild Wars also loses the device during that.
7357 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
7358 This
->style
= style
;
7359 This
->exStyle
= exStyle
;
7362 /* Recreate the primary swapchain's context */
7363 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
7364 if(swapchain
->backBuffer
) {
7365 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
7367 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
7369 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
7370 &swapchain
->presentParms
);
7371 swapchain
->num_contexts
= 1;
7372 This
->activeContext
= swapchain
->context
[0];
7373 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7375 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7377 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7379 create_dummy_textures(This
);
7382 hr
= This
->shader_backend
->shader_alloc_private(iface
);
7384 ERR("Failed to recreate shader private data\n");
7387 hr
= This
->frag_pipe
->alloc_private(iface
);
7389 TRACE("Fragment pipeline private data couldn't be allocated\n");
7393 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7399 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7400 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7401 /** FIXME: always true at the moment **/
7402 if(!bEnableDialogs
) {
7403 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7409 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7410 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7411 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7413 *pParameters
= This
->createParms
;
7417 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7418 IWineD3DSwapChain
*swapchain
;
7420 TRACE("Relaying to swapchain\n");
7422 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7423 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
7424 IWineD3DSwapChain_Release(swapchain
);
7429 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7430 IWineD3DSwapChain
*swapchain
;
7432 TRACE("Relaying to swapchain\n");
7434 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7435 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7436 IWineD3DSwapChain_Release(swapchain
);
7442 /** ********************************************************
7443 * Notification functions
7444 ** ********************************************************/
7445 /** This function must be called in the release of a resource when ref == 0,
7446 * the contents of resource must still be correct,
7447 * any handles to other resource held by the caller must be closed
7448 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7449 *****************************************************/
7450 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7451 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7453 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7454 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7457 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7458 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7460 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7462 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7466 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7467 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7470 TRACE("(%p) : resource %p\n", This
, resource
);
7471 switch(IWineD3DResource_GetType(resource
)){
7472 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7473 case WINED3DRTYPE_SURFACE
: {
7476 /* Cleanup any FBO attachments if d3d is enabled */
7477 if(This
->d3d_initialized
) {
7478 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7479 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7481 TRACE("Last active render target destroyed\n");
7482 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7483 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7484 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7485 * and the lastActiveRenderTarget member shouldn't matter
7488 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7489 TRACE("Activating primary back buffer\n");
7490 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7491 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7492 /* Single buffering environment */
7493 TRACE("Activating primary front buffer\n");
7494 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7496 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7497 /* Implicit render target destroyed, that means the device is being destroyed
7498 * whatever we set here, it shouldn't matter
7500 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7503 /* May happen during ddraw uninitialization */
7504 TRACE("Render target set, but swapchain does not exist!\n");
7505 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7510 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7511 if (This
->fbo_color_attachments
[i
] == (IWineD3DSurface
*)resource
) {
7512 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
7513 set_render_target_fbo(iface
, i
, NULL
);
7514 This
->fbo_color_attachments
[i
] = NULL
;
7517 if (This
->fbo_depth_attachment
== (IWineD3DSurface
*)resource
) {
7518 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
7519 set_depth_stencil_fbo(iface
, NULL
);
7520 This
->fbo_depth_attachment
= NULL
;
7527 case WINED3DRTYPE_TEXTURE
:
7528 case WINED3DRTYPE_CUBETEXTURE
:
7529 case WINED3DRTYPE_VOLUMETEXTURE
:
7530 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7531 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7532 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7533 This
->stateBlock
->textures
[counter
] = NULL
;
7535 if (This
->updateStateBlock
!= This
->stateBlock
){
7536 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7537 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7538 This
->updateStateBlock
->textures
[counter
] = NULL
;
7543 case WINED3DRTYPE_VOLUME
:
7544 /* TODO: nothing really? */
7546 case WINED3DRTYPE_VERTEXBUFFER
:
7547 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7550 TRACE("Cleaning up stream pointers\n");
7552 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7553 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7554 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7556 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7557 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7558 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7559 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7560 /* Set changed flag? */
7563 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) */
7564 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7565 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7566 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7569 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7570 else { /* This shouldn't happen */
7571 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7578 case WINED3DRTYPE_INDEXBUFFER
:
7579 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7580 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7581 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7582 This
->updateStateBlock
->pIndexData
= NULL
;
7585 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7586 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7587 This
->stateBlock
->pIndexData
= NULL
;
7593 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7598 /* Remove the resource from the resourceStore */
7599 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7601 TRACE("Resource released\n");
7605 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7606 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7607 IWineD3DResourceImpl
*resource
, *cursor
;
7609 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7611 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7612 TRACE("enumerating resource %p\n", resource
);
7613 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7614 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7615 if(ret
== S_FALSE
) {
7616 TRACE("Canceling enumeration\n");
7623 /**********************************************************
7624 * IWineD3DDevice VTbl follows
7625 **********************************************************/
7627 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7629 /*** IUnknown methods ***/
7630 IWineD3DDeviceImpl_QueryInterface
,
7631 IWineD3DDeviceImpl_AddRef
,
7632 IWineD3DDeviceImpl_Release
,
7633 /*** IWineD3DDevice methods ***/
7634 IWineD3DDeviceImpl_GetParent
,
7635 /*** Creation methods**/
7636 IWineD3DDeviceImpl_CreateVertexBuffer
,
7637 IWineD3DDeviceImpl_CreateIndexBuffer
,
7638 IWineD3DDeviceImpl_CreateStateBlock
,
7639 IWineD3DDeviceImpl_CreateSurface
,
7640 IWineD3DDeviceImpl_CreateTexture
,
7641 IWineD3DDeviceImpl_CreateVolumeTexture
,
7642 IWineD3DDeviceImpl_CreateVolume
,
7643 IWineD3DDeviceImpl_CreateCubeTexture
,
7644 IWineD3DDeviceImpl_CreateQuery
,
7645 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7646 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7647 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7648 IWineD3DDeviceImpl_CreateVertexShader
,
7649 IWineD3DDeviceImpl_CreatePixelShader
,
7650 IWineD3DDeviceImpl_CreatePalette
,
7651 /*** Odd functions **/
7652 IWineD3DDeviceImpl_Init3D
,
7653 IWineD3DDeviceImpl_Uninit3D
,
7654 IWineD3DDeviceImpl_SetFullscreen
,
7655 IWineD3DDeviceImpl_SetMultithreaded
,
7656 IWineD3DDeviceImpl_EvictManagedResources
,
7657 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7658 IWineD3DDeviceImpl_GetBackBuffer
,
7659 IWineD3DDeviceImpl_GetCreationParameters
,
7660 IWineD3DDeviceImpl_GetDeviceCaps
,
7661 IWineD3DDeviceImpl_GetDirect3D
,
7662 IWineD3DDeviceImpl_GetDisplayMode
,
7663 IWineD3DDeviceImpl_SetDisplayMode
,
7664 IWineD3DDeviceImpl_GetHWND
,
7665 IWineD3DDeviceImpl_SetHWND
,
7666 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7667 IWineD3DDeviceImpl_GetRasterStatus
,
7668 IWineD3DDeviceImpl_GetSwapChain
,
7669 IWineD3DDeviceImpl_Reset
,
7670 IWineD3DDeviceImpl_SetDialogBoxMode
,
7671 IWineD3DDeviceImpl_SetCursorProperties
,
7672 IWineD3DDeviceImpl_SetCursorPosition
,
7673 IWineD3DDeviceImpl_ShowCursor
,
7674 IWineD3DDeviceImpl_TestCooperativeLevel
,
7675 /*** Getters and setters **/
7676 IWineD3DDeviceImpl_SetClipPlane
,
7677 IWineD3DDeviceImpl_GetClipPlane
,
7678 IWineD3DDeviceImpl_SetClipStatus
,
7679 IWineD3DDeviceImpl_GetClipStatus
,
7680 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7681 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7682 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7683 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7684 IWineD3DDeviceImpl_SetFVF
,
7685 IWineD3DDeviceImpl_GetFVF
,
7686 IWineD3DDeviceImpl_SetGammaRamp
,
7687 IWineD3DDeviceImpl_GetGammaRamp
,
7688 IWineD3DDeviceImpl_SetIndices
,
7689 IWineD3DDeviceImpl_GetIndices
,
7690 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7691 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7692 IWineD3DDeviceImpl_SetLight
,
7693 IWineD3DDeviceImpl_GetLight
,
7694 IWineD3DDeviceImpl_SetLightEnable
,
7695 IWineD3DDeviceImpl_GetLightEnable
,
7696 IWineD3DDeviceImpl_SetMaterial
,
7697 IWineD3DDeviceImpl_GetMaterial
,
7698 IWineD3DDeviceImpl_SetNPatchMode
,
7699 IWineD3DDeviceImpl_GetNPatchMode
,
7700 IWineD3DDeviceImpl_SetPaletteEntries
,
7701 IWineD3DDeviceImpl_GetPaletteEntries
,
7702 IWineD3DDeviceImpl_SetPixelShader
,
7703 IWineD3DDeviceImpl_GetPixelShader
,
7704 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7705 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7706 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7707 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7708 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7709 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7710 IWineD3DDeviceImpl_SetRenderState
,
7711 IWineD3DDeviceImpl_GetRenderState
,
7712 IWineD3DDeviceImpl_SetRenderTarget
,
7713 IWineD3DDeviceImpl_GetRenderTarget
,
7714 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7715 IWineD3DDeviceImpl_SetSamplerState
,
7716 IWineD3DDeviceImpl_GetSamplerState
,
7717 IWineD3DDeviceImpl_SetScissorRect
,
7718 IWineD3DDeviceImpl_GetScissorRect
,
7719 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7720 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7721 IWineD3DDeviceImpl_SetStreamSource
,
7722 IWineD3DDeviceImpl_GetStreamSource
,
7723 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7724 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7725 IWineD3DDeviceImpl_SetTexture
,
7726 IWineD3DDeviceImpl_GetTexture
,
7727 IWineD3DDeviceImpl_SetTextureStageState
,
7728 IWineD3DDeviceImpl_GetTextureStageState
,
7729 IWineD3DDeviceImpl_SetTransform
,
7730 IWineD3DDeviceImpl_GetTransform
,
7731 IWineD3DDeviceImpl_SetVertexDeclaration
,
7732 IWineD3DDeviceImpl_GetVertexDeclaration
,
7733 IWineD3DDeviceImpl_SetVertexShader
,
7734 IWineD3DDeviceImpl_GetVertexShader
,
7735 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7736 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7737 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7738 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7739 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7740 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7741 IWineD3DDeviceImpl_SetViewport
,
7742 IWineD3DDeviceImpl_GetViewport
,
7743 IWineD3DDeviceImpl_MultiplyTransform
,
7744 IWineD3DDeviceImpl_ValidateDevice
,
7745 IWineD3DDeviceImpl_ProcessVertices
,
7746 /*** State block ***/
7747 IWineD3DDeviceImpl_BeginStateBlock
,
7748 IWineD3DDeviceImpl_EndStateBlock
,
7749 /*** Scene management ***/
7750 IWineD3DDeviceImpl_BeginScene
,
7751 IWineD3DDeviceImpl_EndScene
,
7752 IWineD3DDeviceImpl_Present
,
7753 IWineD3DDeviceImpl_Clear
,
7755 IWineD3DDeviceImpl_DrawPrimitive
,
7756 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7757 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7758 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7759 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7760 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7761 IWineD3DDeviceImpl_DrawRectPatch
,
7762 IWineD3DDeviceImpl_DrawTriPatch
,
7763 IWineD3DDeviceImpl_DeletePatch
,
7764 IWineD3DDeviceImpl_ColorFill
,
7765 IWineD3DDeviceImpl_UpdateTexture
,
7766 IWineD3DDeviceImpl_UpdateSurface
,
7767 IWineD3DDeviceImpl_GetFrontBufferData
,
7768 /*** object tracking ***/
7769 IWineD3DDeviceImpl_ResourceReleased
,
7770 IWineD3DDeviceImpl_EnumResources
7773 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl
=
7775 /*** IUnknown methods ***/
7776 IWineD3DDeviceImpl_QueryInterface
,
7777 IWineD3DDeviceImpl_AddRef
,
7778 IWineD3DDeviceImpl_Release
,
7779 /*** IWineD3DDevice methods ***/
7780 IWineD3DDeviceImpl_GetParent
,
7781 /*** Creation methods**/
7782 IWineD3DDeviceImpl_CreateVertexBuffer
,
7783 IWineD3DDeviceImpl_CreateIndexBuffer
,
7784 IWineD3DDeviceImpl_CreateStateBlock
,
7785 IWineD3DDeviceImpl_CreateSurface
,
7786 IWineD3DDeviceImpl_CreateTexture
,
7787 IWineD3DDeviceImpl_CreateVolumeTexture
,
7788 IWineD3DDeviceImpl_CreateVolume
,
7789 IWineD3DDeviceImpl_CreateCubeTexture
,
7790 IWineD3DDeviceImpl_CreateQuery
,
7791 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7792 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7793 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7794 IWineD3DDeviceImpl_CreateVertexShader
,
7795 IWineD3DDeviceImpl_CreatePixelShader
,
7796 IWineD3DDeviceImpl_CreatePalette
,
7797 /*** Odd functions **/
7798 IWineD3DDeviceImpl_Init3D
,
7799 IWineD3DDeviceImpl_Uninit3D
,
7800 IWineD3DDeviceImpl_SetFullscreen
,
7801 IWineD3DDeviceImpl_SetMultithreaded
,
7802 IWineD3DDeviceImpl_EvictManagedResources
,
7803 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7804 IWineD3DDeviceImpl_GetBackBuffer
,
7805 IWineD3DDeviceImpl_GetCreationParameters
,
7806 IWineD3DDeviceImpl_GetDeviceCaps
,
7807 IWineD3DDeviceImpl_GetDirect3D
,
7808 IWineD3DDeviceImpl_GetDisplayMode
,
7809 IWineD3DDeviceImpl_SetDisplayMode
,
7810 IWineD3DDeviceImpl_GetHWND
,
7811 IWineD3DDeviceImpl_SetHWND
,
7812 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7813 IWineD3DDeviceImpl_GetRasterStatus
,
7814 IWineD3DDeviceImpl_GetSwapChain
,
7815 IWineD3DDeviceImpl_Reset
,
7816 IWineD3DDeviceImpl_SetDialogBoxMode
,
7817 IWineD3DDeviceImpl_SetCursorProperties
,
7818 IWineD3DDeviceImpl_SetCursorPosition
,
7819 IWineD3DDeviceImpl_ShowCursor
,
7820 IWineD3DDeviceImpl_TestCooperativeLevel
,
7821 /*** Getters and setters **/
7822 IWineD3DDeviceImpl_SetClipPlane
,
7823 IWineD3DDeviceImpl_GetClipPlane
,
7824 IWineD3DDeviceImpl_SetClipStatus
,
7825 IWineD3DDeviceImpl_GetClipStatus
,
7826 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7827 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7828 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7829 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7830 IWineD3DDeviceImpl_SetFVF
,
7831 IWineD3DDeviceImpl_GetFVF
,
7832 IWineD3DDeviceImpl_SetGammaRamp
,
7833 IWineD3DDeviceImpl_GetGammaRamp
,
7834 IWineD3DDeviceImpl_SetIndices
,
7835 IWineD3DDeviceImpl_GetIndices
,
7836 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7837 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7838 IWineD3DDeviceImpl_SetLight
,
7839 IWineD3DDeviceImpl_GetLight
,
7840 IWineD3DDeviceImpl_SetLightEnable
,
7841 IWineD3DDeviceImpl_GetLightEnable
,
7842 IWineD3DDeviceImpl_SetMaterial
,
7843 IWineD3DDeviceImpl_GetMaterial
,
7844 IWineD3DDeviceImpl_SetNPatchMode
,
7845 IWineD3DDeviceImpl_GetNPatchMode
,
7846 IWineD3DDeviceImpl_SetPaletteEntries
,
7847 IWineD3DDeviceImpl_GetPaletteEntries
,
7848 IWineD3DDeviceImpl_SetPixelShader
,
7849 IWineD3DDeviceImpl_GetPixelShader
,
7850 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7851 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7852 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7853 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7854 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst
,
7855 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7856 IWineD3DDeviceImpl_SetRenderState
,
7857 IWineD3DDeviceImpl_GetRenderState
,
7858 IWineD3DDeviceImpl_SetRenderTarget
,
7859 IWineD3DDeviceImpl_GetRenderTarget
,
7860 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7861 IWineD3DDeviceImpl_SetSamplerState
,
7862 IWineD3DDeviceImpl_GetSamplerState
,
7863 IWineD3DDeviceImpl_SetScissorRect
,
7864 IWineD3DDeviceImpl_GetScissorRect
,
7865 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7866 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7867 IWineD3DDeviceImpl_SetStreamSource
,
7868 IWineD3DDeviceImpl_GetStreamSource
,
7869 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7870 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7871 IWineD3DDeviceImpl_SetTexture
,
7872 IWineD3DDeviceImpl_GetTexture
,
7873 IWineD3DDeviceImpl_SetTextureStageState
,
7874 IWineD3DDeviceImpl_GetTextureStageState
,
7875 IWineD3DDeviceImpl_SetTransform
,
7876 IWineD3DDeviceImpl_GetTransform
,
7877 IWineD3DDeviceImpl_SetVertexDeclaration
,
7878 IWineD3DDeviceImpl_GetVertexDeclaration
,
7879 IWineD3DDeviceImpl_SetVertexShader
,
7880 IWineD3DDeviceImpl_GetVertexShader
,
7881 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7882 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7883 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7884 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7885 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst
,
7886 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7887 IWineD3DDeviceImpl_SetViewport
,
7888 IWineD3DDeviceImpl_GetViewport
,
7889 IWineD3DDeviceImpl_MultiplyTransform
,
7890 IWineD3DDeviceImpl_ValidateDevice
,
7891 IWineD3DDeviceImpl_ProcessVertices
,
7892 /*** State block ***/
7893 IWineD3DDeviceImpl_BeginStateBlock
,
7894 IWineD3DDeviceImpl_EndStateBlock
,
7895 /*** Scene management ***/
7896 IWineD3DDeviceImpl_BeginScene
,
7897 IWineD3DDeviceImpl_EndScene
,
7898 IWineD3DDeviceImpl_Present
,
7899 IWineD3DDeviceImpl_Clear
,
7901 IWineD3DDeviceImpl_DrawPrimitive
,
7902 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7903 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7904 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7905 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7906 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7907 IWineD3DDeviceImpl_DrawRectPatch
,
7908 IWineD3DDeviceImpl_DrawTriPatch
,
7909 IWineD3DDeviceImpl_DeletePatch
,
7910 IWineD3DDeviceImpl_ColorFill
,
7911 IWineD3DDeviceImpl_UpdateTexture
,
7912 IWineD3DDeviceImpl_UpdateSurface
,
7913 IWineD3DDeviceImpl_GetFrontBufferData
,
7914 /*** object tracking ***/
7915 IWineD3DDeviceImpl_ResourceReleased
,
7916 IWineD3DDeviceImpl_EnumResources
7919 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7920 WINED3DRS_ALPHABLENDENABLE
,
7921 WINED3DRS_ALPHAFUNC
,
7922 WINED3DRS_ALPHAREF
,
7923 WINED3DRS_ALPHATESTENABLE
,
7925 WINED3DRS_COLORWRITEENABLE
,
7926 WINED3DRS_DESTBLEND
,
7927 WINED3DRS_DITHERENABLE
,
7928 WINED3DRS_FILLMODE
,
7929 WINED3DRS_FOGDENSITY
,
7931 WINED3DRS_FOGSTART
,
7932 WINED3DRS_LASTPIXEL
,
7933 WINED3DRS_SHADEMODE
,
7934 WINED3DRS_SRCBLEND
,
7935 WINED3DRS_STENCILENABLE
,
7936 WINED3DRS_STENCILFAIL
,
7937 WINED3DRS_STENCILFUNC
,
7938 WINED3DRS_STENCILMASK
,
7939 WINED3DRS_STENCILPASS
,
7940 WINED3DRS_STENCILREF
,
7941 WINED3DRS_STENCILWRITEMASK
,
7942 WINED3DRS_STENCILZFAIL
,
7943 WINED3DRS_TEXTUREFACTOR
,
7954 WINED3DRS_ZWRITEENABLE
7957 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7958 WINED3DTSS_ADDRESSW
,
7959 WINED3DTSS_ALPHAARG0
,
7960 WINED3DTSS_ALPHAARG1
,
7961 WINED3DTSS_ALPHAARG2
,
7962 WINED3DTSS_ALPHAOP
,
7963 WINED3DTSS_BUMPENVLOFFSET
,
7964 WINED3DTSS_BUMPENVLSCALE
,
7965 WINED3DTSS_BUMPENVMAT00
,
7966 WINED3DTSS_BUMPENVMAT01
,
7967 WINED3DTSS_BUMPENVMAT10
,
7968 WINED3DTSS_BUMPENVMAT11
,
7969 WINED3DTSS_COLORARG0
,
7970 WINED3DTSS_COLORARG1
,
7971 WINED3DTSS_COLORARG2
,
7972 WINED3DTSS_COLOROP
,
7973 WINED3DTSS_RESULTARG
,
7974 WINED3DTSS_TEXCOORDINDEX
,
7975 WINED3DTSS_TEXTURETRANSFORMFLAGS
7978 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7979 WINED3DSAMP_ADDRESSU
,
7980 WINED3DSAMP_ADDRESSV
,
7981 WINED3DSAMP_ADDRESSW
,
7982 WINED3DSAMP_BORDERCOLOR
,
7983 WINED3DSAMP_MAGFILTER
,
7984 WINED3DSAMP_MINFILTER
,
7985 WINED3DSAMP_MIPFILTER
,
7986 WINED3DSAMP_MIPMAPLODBIAS
,
7987 WINED3DSAMP_MAXMIPLEVEL
,
7988 WINED3DSAMP_MAXANISOTROPY
,
7989 WINED3DSAMP_SRGBTEXTURE
,
7990 WINED3DSAMP_ELEMENTINDEX
7993 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7995 WINED3DRS_AMBIENTMATERIALSOURCE
,
7996 WINED3DRS_CLIPPING
,
7997 WINED3DRS_CLIPPLANEENABLE
,
7998 WINED3DRS_COLORVERTEX
,
7999 WINED3DRS_DIFFUSEMATERIALSOURCE
,
8000 WINED3DRS_EMISSIVEMATERIALSOURCE
,
8001 WINED3DRS_FOGDENSITY
,
8003 WINED3DRS_FOGSTART
,
8004 WINED3DRS_FOGTABLEMODE
,
8005 WINED3DRS_FOGVERTEXMODE
,
8006 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
8007 WINED3DRS_LIGHTING
,
8008 WINED3DRS_LOCALVIEWER
,
8009 WINED3DRS_MULTISAMPLEANTIALIAS
,
8010 WINED3DRS_MULTISAMPLEMASK
,
8011 WINED3DRS_NORMALIZENORMALS
,
8012 WINED3DRS_PATCHEDGESTYLE
,
8013 WINED3DRS_POINTSCALE_A
,
8014 WINED3DRS_POINTSCALE_B
,
8015 WINED3DRS_POINTSCALE_C
,
8016 WINED3DRS_POINTSCALEENABLE
,
8017 WINED3DRS_POINTSIZE
,
8018 WINED3DRS_POINTSIZE_MAX
,
8019 WINED3DRS_POINTSIZE_MIN
,
8020 WINED3DRS_POINTSPRITEENABLE
,
8021 WINED3DRS_RANGEFOGENABLE
,
8022 WINED3DRS_SPECULARMATERIALSOURCE
,
8023 WINED3DRS_TWEENFACTOR
,
8024 WINED3DRS_VERTEXBLEND
,
8025 WINED3DRS_CULLMODE
,
8029 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
8030 WINED3DTSS_TEXCOORDINDEX
,
8031 WINED3DTSS_TEXTURETRANSFORMFLAGS
8034 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
8035 WINED3DSAMP_DMAPOFFSET
8038 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
8039 DWORD rep
= This
->StateTable
[state
].representative
;
8043 WineD3DContext
*context
;
8046 for(i
= 0; i
< This
->numContexts
; i
++) {
8047 context
= This
->contexts
[i
];
8048 if(isStateDirty(context
, rep
)) continue;
8050 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
8053 context
->isStateDirty
[idx
] |= (1 << shift
);
8057 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8058 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
8059 /* The drawable size of a pbuffer render target is the current pbuffer size
8061 *width
= dev
->pbufferWidth
;
8062 *height
= dev
->pbufferHeight
;
8065 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8066 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8068 *width
= This
->pow2Width
;
8069 *height
= This
->pow2Height
;
8072 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8073 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
8074 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8075 * current context's drawable, which is the size of the back buffer of the swapchain
8076 * the active context belongs to. The back buffer of the swapchain is stored as the
8077 * surface the context belongs to.
8079 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
8080 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;