2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
138 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
140 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
141 if (IsEqualGUID(riid
, &IID_IUnknown
)
142 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
143 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
144 IUnknown_AddRef(iface
);
149 return E_NOINTERFACE
;
152 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
154 ULONG refCount
= InterlockedIncrement(&This
->ref
);
156 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
160 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
161 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
162 ULONG refCount
= InterlockedDecrement(&This
->ref
);
164 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This
->resources
)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
173 dumpResources(&This
->resources
);
176 if(This
->contexts
) ERR("Context array not freed!\n");
177 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
178 This
->haveHardwareCursor
= FALSE
;
180 IWineD3D_Release(This
->wineD3D
);
181 This
->wineD3D
= NULL
;
182 HeapFree(GetProcessHeap(), 0, This
);
183 TRACE("Freed device %p\n", This
);
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
193 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
194 *pParent
= This
->parent
;
195 IUnknown_AddRef(This
->parent
);
199 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
200 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
202 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
203 IWineD3DVertexBufferImpl
*object
;
204 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
205 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer
= NULL
;
211 return WINED3DERR_INVALIDCALL
;
212 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer
= NULL
;
218 return WINED3DERR_INVALIDCALL
;
221 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
223 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
224 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion
<= 7 && conv
) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
253 object
->Flags
|= VBFLAG_CREATEVBO
;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
259 GLenum error
, glUsage
;
260 TRACE("Creating VBO for Index Buffer %p\n", object
);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
273 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
274 error
= glGetError();
275 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
281 error
= glGetError();
282 if(error
!= GL_NO_ERROR
) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage
= GL_STATIC_DRAW_ARB
;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
292 error
= glGetError();
293 if(error
!= GL_NO_ERROR
) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
298 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
308 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
309 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
310 HANDLE
*sharedHandle
, IUnknown
*parent
) {
311 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
312 IWineD3DIndexBufferImpl
*object
;
313 TRACE("(%p) Creating index buffer\n", This
);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
318 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
319 CreateIndexBufferVBO(This
, object
);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
323 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
324 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
329 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
332 IWineD3DStateBlockImpl
*object
;
336 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
337 object
->blockType
= Type
;
339 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
340 list_init(&object
->lightMap
[i
]);
343 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type
== WINED3DSBT_INIT
) {
346 /* Don't bother increasing the reference count otherwise a device will never
347 be freed due to circular dependencies */
351 temp_result
= allocate_shader_constants(object
);
352 if (WINED3D_OK
!= temp_result
)
355 /* Otherwise, might as well set the whole state block to the appropriate values */
356 if (This
->stateBlock
!= NULL
)
357 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
359 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
361 /* Reset the ref and type after kludging it */
362 object
->wineD3DDevice
= This
;
364 object
->blockType
= Type
;
366 TRACE("Updating changed flags appropriate for type %d\n", Type
);
368 if (Type
== WINED3DSBT_ALL
) {
370 TRACE("ALL => Pretend everything has changed\n");
371 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
373 /* Lights are not part of the changed / set structure */
374 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
376 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
377 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
378 light
->changed
= TRUE
;
379 light
->enabledChanged
= TRUE
;
382 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
383 object
->contained_render_states
[j
- 1] = j
;
385 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
386 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
387 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
388 object
->contained_transform_states
[j
- 1] = j
;
390 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
391 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
392 object
->contained_vs_consts_f
[j
] = j
;
394 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
395 for(j
= 0; j
< MAX_CONST_I
; j
++) {
396 object
->contained_vs_consts_i
[j
] = j
;
398 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
399 for(j
= 0; j
< MAX_CONST_B
; j
++) {
400 object
->contained_vs_consts_b
[j
] = j
;
402 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
403 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
404 object
->contained_ps_consts_f
[j
] = j
;
406 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
407 for(j
= 0; j
< MAX_CONST_I
; j
++) {
408 object
->contained_ps_consts_i
[j
] = j
;
410 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
411 for(j
= 0; j
< MAX_CONST_B
; j
++) {
412 object
->contained_ps_consts_b
[j
] = j
;
414 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
415 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
416 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
417 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
418 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
419 object
->num_contained_tss_states
++;
422 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
423 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
424 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
425 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
426 object
->num_contained_sampler_states
++;
430 for(i
= 0; i
< MAX_STREAMS
; i
++) {
431 if(object
->streamSource
[i
]) {
432 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
435 if(object
->pIndexData
) {
436 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
438 if(object
->vertexShader
) {
439 IWineD3DVertexShader_AddRef(object
->vertexShader
);
441 if(object
->pixelShader
) {
442 IWineD3DPixelShader_AddRef(object
->pixelShader
);
445 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
447 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
448 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
450 object
->changed
.pixelShader
= TRUE
;
452 /* Pixel Shader Constants */
453 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
) {
454 object
->contained_ps_consts_f
[i
] = i
;
455 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
457 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
458 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
459 object
->contained_ps_consts_b
[i
] = i
;
460 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
462 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
463 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
464 object
->contained_ps_consts_i
[i
] = i
;
465 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
467 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
469 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
470 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
471 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
473 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
474 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
475 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
476 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
477 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
478 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
479 object
->num_contained_tss_states
++;
482 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
483 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
484 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
485 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
486 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
487 object
->num_contained_sampler_states
++;
490 if(object
->pixelShader
) {
491 IWineD3DPixelShader_AddRef(object
->pixelShader
);
494 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
495 * on them. This makes releasing the buffer easier
497 for(i
= 0; i
< MAX_STREAMS
; i
++) {
498 object
->streamSource
[i
] = NULL
;
500 object
->pIndexData
= NULL
;
501 object
->vertexShader
= NULL
;
503 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
505 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
506 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
508 object
->changed
.vertexShader
= TRUE
;
510 /* Vertex Shader Constants */
511 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
512 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
513 object
->contained_vs_consts_f
[i
] = i
;
515 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
516 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
517 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
518 object
->contained_vs_consts_b
[i
] = i
;
520 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
521 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
522 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
523 object
->contained_vs_consts_i
[i
] = i
;
525 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
526 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
527 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
528 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
530 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
531 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
532 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
533 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
534 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
535 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
536 object
->num_contained_tss_states
++;
539 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
540 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
541 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
542 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
543 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
544 object
->num_contained_sampler_states
++;
548 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
550 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
551 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
552 light
->changed
= TRUE
;
553 light
->enabledChanged
= TRUE
;
557 for(i
= 0; i
< MAX_STREAMS
; i
++) {
558 if(object
->streamSource
[i
]) {
559 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
562 if(object
->vertexShader
) {
563 IWineD3DVertexShader_AddRef(object
->vertexShader
);
565 object
->pIndexData
= NULL
;
566 object
->pixelShader
= NULL
;
568 FIXME("Unrecognized state block type %d\n", Type
);
571 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
575 /* ************************************
577 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
580 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
582 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.
584 ******************************** */
586 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
) {
587 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
588 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
589 unsigned int Size
= 1;
590 const GlPixelFormatDesc
*glDesc
;
591 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
593 TRACE("(%p) Create surface\n",This
);
595 /** FIXME: Check ranges on the inputs are valid
598 * [in] Quality level. The valid range is between zero and one less than the level
599 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
600 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
601 * values of paired render targets, depth stencil surfaces, and the MultiSample type
603 *******************************/
608 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
610 * If this flag is set, the contents of the depth stencil buffer will be
611 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
612 * with a different depth surface.
614 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
615 ***************************/
617 if(MultisampleQuality
> 0) {
618 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
619 MultisampleQuality
=0;
622 /** FIXME: Check that the format is supported
624 *******************************/
626 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
627 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
629 *********************************/
630 mul_4w
= (Width
+ 3) & ~3;
631 mul_4h
= (Height
+ 3) & ~3;
632 if (WINED3DFMT_UNKNOWN
== Format
) {
634 } else if (Format
== WINED3DFMT_DXT1
) {
635 /* DXT1 is half byte per pixel */
636 Size
= (mul_4w
* tableEntry
->bpp
* mul_4h
) >> 1;
638 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
639 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
||
640 Format
== WINED3DFMT_ATI2N
) {
641 Size
= (mul_4w
* tableEntry
->bpp
* mul_4h
);
643 /* The pitch is a multiple of 4 bytes */
644 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
648 if(glDesc
->heightscale
!= 0.0) Size
*= glDesc
->heightscale
;
650 /** Create and initialise the surface resource **/
651 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
652 /* "Standalone" surface */
653 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
655 object
->currentDesc
.Width
= Width
;
656 object
->currentDesc
.Height
= Height
;
657 object
->currentDesc
.MultiSampleType
= MultiSample
;
658 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
659 object
->glDescription
.level
= Level
;
660 object
->heightscale
= glDesc
->heightscale
!= 0.0 ? glDesc
->heightscale
: 1.0;
661 list_init(&object
->overlays
);
664 object
->Flags
= SFLAG_NORMCOORD
; /* Default to normalized coords */
665 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
666 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
667 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
670 if (WINED3DFMT_UNKNOWN
!= Format
) {
671 object
->bytesPerPixel
= tableEntry
->bpp
;
673 object
->bytesPerPixel
= 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
685 case WINED3DPOOL_SCRATCH
:
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
691 case WINED3DPOOL_SYSTEMMEM
:
692 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED
:
695 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
699 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
701 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
709 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
717 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
719 /* Look at the implementation and set the correct Vtable */
722 /* Check if a 3D adapter is available when creating gl surfaces */
724 ERR("OpenGL surfaces are not available without opengl\n");
725 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
726 HeapFree(GetProcessHeap(), 0, object
);
727 return WINED3DERR_NOTAVAILABLE
;
732 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
736 /* To be sure to catch this */
737 ERR("Unknown requested surface implementation %d!\n", Impl
);
738 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
739 return WINED3DERR_INVALIDCALL
;
742 list_init(&object
->renderbuffers
);
744 /* Call the private setup routine */
745 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
749 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
750 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
751 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
752 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
754 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
755 IWineD3DTextureImpl
*object
;
760 unsigned int pow2Width
;
761 unsigned int pow2Height
;
762 const GlPixelFormatDesc
*glDesc
;
763 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
765 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
766 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
767 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
769 /* TODO: It should only be possible to create textures for formats
770 that are reported as supported */
771 if (WINED3DFMT_UNKNOWN
>= Format
) {
772 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
773 return WINED3DERR_INVALIDCALL
;
776 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
777 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
778 object
->width
= Width
;
779 object
->height
= Height
;
781 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
782 object
->baseTexture
.minMipLookup
= &minMipLookup
;
783 object
->baseTexture
.magLookup
= &magLookup
;
785 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
786 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
789 /** Non-power2 support **/
790 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
794 /* Find the nearest pow2 match */
795 pow2Width
= pow2Height
= 1;
796 while (pow2Width
< Width
) pow2Width
<<= 1;
797 while (pow2Height
< Height
) pow2Height
<<= 1;
799 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
801 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
802 HeapFree(GetProcessHeap(), 0, object
);
804 return WINED3DERR_INVALIDCALL
;
811 /** FIXME: add support for real non-power-two if it's provided by the video card **/
812 /* Precalculated scaling for 'faked' non power of two texture coords.
813 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
814 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
815 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
817 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT
) && (Width
!= pow2Width
|| Height
!= pow2Height
)) {
818 object
->baseTexture
.pow2Matrix
[0] = 1.0;
819 object
->baseTexture
.pow2Matrix
[5] = 1.0;
820 object
->baseTexture
.pow2Matrix
[10] = 1.0;
821 object
->baseTexture
.pow2Matrix
[15] = 1.0;
822 object
->target
= GL_TEXTURE_2D
;
823 object
->cond_np2
= TRUE
;
824 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
825 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
826 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
827 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
829 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
830 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
831 object
->baseTexture
.pow2Matrix
[10] = 1.0;
832 object
->baseTexture
.pow2Matrix
[15] = 1.0;
833 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
834 object
->cond_np2
= TRUE
;
835 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
837 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
838 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
839 object
->baseTexture
.pow2Matrix
[10] = 1.0;
840 object
->baseTexture
.pow2Matrix
[15] = 1.0;
841 object
->target
= GL_TEXTURE_2D
;
842 object
->cond_np2
= FALSE
;
844 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
846 /* Calculate levels for mip mapping */
847 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
848 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
849 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
850 return WINED3DERR_INVALIDCALL
;
853 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL
;
856 object
->baseTexture
.levels
= 1;
857 } else if (Levels
== 0) {
858 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
859 object
->baseTexture
.levels
++;
862 while (tmpW
> 1 || tmpH
> 1) {
863 tmpW
= max(1, tmpW
>> 1);
864 tmpH
= max(1, tmpH
>> 1);
865 object
->baseTexture
.levels
++;
867 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
870 /* Generate all the surfaces */
873 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
875 /* use the callback to create the texture surface */
876 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
877 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
878 FIXME("Failed to create surface %p\n", object
);
880 object
->surfaces
[i
] = NULL
;
881 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
887 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
888 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
889 surface_set_texture_target(object
->surfaces
[i
], object
->target
);
890 /* calculate the next mipmap level */
891 tmpW
= max(1, tmpW
>> 1);
892 tmpH
= max(1, tmpH
>> 1);
894 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
896 TRACE("(%p) : Created texture %p\n", This
, object
);
900 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
901 UINT Width
, UINT Height
, UINT Depth
,
902 UINT Levels
, DWORD Usage
,
903 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
904 IWineD3DVolumeTexture
**ppVolumeTexture
,
905 HANDLE
*pSharedHandle
, IUnknown
*parent
,
906 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
908 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
909 IWineD3DVolumeTextureImpl
*object
;
914 const GlPixelFormatDesc
*glDesc
;
916 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
918 /* TODO: It should only be possible to create textures for formats
919 that are reported as supported */
920 if (WINED3DFMT_UNKNOWN
>= Format
) {
921 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
922 return WINED3DERR_INVALIDCALL
;
924 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
925 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
926 return WINED3DERR_INVALIDCALL
;
929 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
930 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
932 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
933 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
935 object
->width
= Width
;
936 object
->height
= Height
;
937 object
->depth
= Depth
;
939 /* Is NP2 support for volumes needed? */
940 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
941 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
942 object
->baseTexture
.pow2Matrix
[10] = 1.0;
943 object
->baseTexture
.pow2Matrix
[15] = 1.0;
945 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
946 object
->baseTexture
.minMipLookup
= &minMipLookup
;
947 object
->baseTexture
.magLookup
= &magLookup
;
949 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
950 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
953 /* Calculate levels for mip mapping */
954 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
955 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL
;
960 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL
;
963 object
->baseTexture
.levels
= 1;
964 } else if (Levels
== 0) {
965 object
->baseTexture
.levels
++;
969 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
970 tmpW
= max(1, tmpW
>> 1);
971 tmpH
= max(1, tmpH
>> 1);
972 tmpD
= max(1, tmpD
>> 1);
973 object
->baseTexture
.levels
++;
975 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
978 /* Generate all the surfaces */
983 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
986 /* Create the volume */
987 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
988 &object
->volumes
[i
], pSharedHandle
);
991 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
992 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
993 *ppVolumeTexture
= NULL
;
997 /* Set its container to this object */
998 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1000 /* calculate the next mipmap level */
1001 tmpW
= max(1, tmpW
>> 1);
1002 tmpH
= max(1, tmpH
>> 1);
1003 tmpD
= max(1, tmpD
>> 1);
1005 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1007 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1008 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1012 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1013 UINT Width
, UINT Height
, UINT Depth
,
1015 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1016 IWineD3DVolume
** ppVolume
,
1017 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1019 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1020 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1021 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1023 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1024 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1025 return WINED3DERR_INVALIDCALL
;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1030 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1031 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1033 object
->currentDesc
.Width
= Width
;
1034 object
->currentDesc
.Height
= Height
;
1035 object
->currentDesc
.Depth
= Depth
;
1036 object
->bytesPerPixel
= formatDesc
->bpp
;
1038 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1039 object
->lockable
= TRUE
;
1040 object
->locked
= FALSE
;
1041 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1042 object
->dirty
= TRUE
;
1044 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1047 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1048 UINT Levels
, DWORD Usage
,
1049 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1050 IWineD3DCubeTexture
**ppCubeTexture
,
1051 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1052 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1054 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1055 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1059 unsigned int pow2EdgeLength
;
1060 const GlPixelFormatDesc
*glDesc
;
1061 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1063 /* TODO: It should only be possible to create textures for formats
1064 that are reported as supported */
1065 if (WINED3DFMT_UNKNOWN
>= Format
) {
1066 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1067 return WINED3DERR_INVALIDCALL
;
1070 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1071 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1072 return WINED3DERR_INVALIDCALL
;
1075 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1076 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1078 TRACE("(%p) Create Cube Texture\n", This
);
1080 /* Find the nearest pow2 match */
1082 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1084 object
->edgeLength
= EdgeLength
;
1086 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
1087 /* Precalculated scaling for 'faked' non power of two texture coords */
1088 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
1089 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
1090 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1091 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1093 /* Precalculated scaling for 'faked' non power of two texture coords */
1094 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1095 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1096 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1097 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
;
1124 object
->baseTexture
.levels
= 1;
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
++) {
1141 static const GLenum cube_targets
[6] = {
1142 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
1143 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
1144 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
1145 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
1146 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
1147 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1150 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1151 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1153 if(hr
!= WINED3D_OK
) {
1157 for (l
= 0; l
< j
; l
++) {
1158 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1160 for (k
= 0; k
< i
; k
++) {
1161 for (l
= 0; l
< 6; l
++) {
1162 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1166 FIXME("(%p) Failed to create surface\n",object
);
1167 HeapFree(GetProcessHeap(),0,object
);
1168 *ppCubeTexture
= NULL
;
1171 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1172 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1173 surface_set_texture_target(object
->surfaces
[j
][i
], cube_targets
[j
]);
1175 tmpW
= max(1, tmpW
>> 1);
1177 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1179 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1180 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1184 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1185 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1186 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1187 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1188 const IWineD3DQueryVtbl
*vtable
;
1190 /* Just a check to see if we support this type of query */
1192 case WINED3DQUERYTYPE_OCCLUSION
:
1193 TRACE("(%p) occlusion query\n", This
);
1194 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1197 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1199 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1202 case WINED3DQUERYTYPE_EVENT
:
1203 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1204 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1205 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1207 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1209 vtable
= &IWineD3DEventQuery_Vtbl
;
1213 case WINED3DQUERYTYPE_VCACHE
:
1214 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1215 case WINED3DQUERYTYPE_VERTEXSTATS
:
1216 case WINED3DQUERYTYPE_TIMESTAMP
:
1217 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1218 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1219 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1220 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1221 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1222 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1223 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1224 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1226 /* Use the base Query vtable until we have a special one for each query */
1227 vtable
= &IWineD3DQuery_Vtbl
;
1228 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1230 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1234 D3DCREATEOBJECTINSTANCE(object
, Query
)
1235 object
->lpVtbl
= vtable
;
1236 object
->type
= Type
;
1237 object
->state
= QUERY_CREATED
;
1238 /* allocated the 'extended' data based on the type of query requested */
1240 case WINED3DQUERYTYPE_OCCLUSION
:
1241 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1242 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1244 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1245 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1246 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1249 case WINED3DQUERYTYPE_EVENT
:
1250 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1251 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1253 if(GL_SUPPORT(APPLE_FENCE
)) {
1254 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1255 checkGLcall("glGenFencesAPPLE");
1256 } else if(GL_SUPPORT(NV_FENCE
)) {
1257 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1258 checkGLcall("glGenFencesNV");
1262 case WINED3DQUERYTYPE_VCACHE
:
1263 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1264 case WINED3DQUERYTYPE_VERTEXSTATS
:
1265 case WINED3DQUERYTYPE_TIMESTAMP
:
1266 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1267 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1268 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1269 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1270 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1271 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1272 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1273 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1275 object
->extendedData
= 0;
1276 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1278 TRACE("(%p) : Created Query %p\n", This
, object
);
1282 /*****************************************************************************
1283 * IWineD3DDeviceImpl_SetupFullscreenWindow
1285 * Helper function that modifies a HWND's Style and ExStyle for proper
1289 * iface: Pointer to the IWineD3DDevice interface
1290 * window: Window to setup
1292 *****************************************************************************/
1293 static LONG
fullscreen_style(LONG orig_style
) {
1294 LONG style
= orig_style
;
1295 style
&= ~WS_CAPTION
;
1296 style
&= ~WS_THICKFRAME
;
1298 /* Make sure the window is managed, otherwise we won't get keyboard input */
1299 style
|= WS_POPUP
| WS_SYSMENU
;
1304 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1305 LONG exStyle
= orig_exStyle
;
1307 /* Filter out window decorations */
1308 exStyle
&= ~WS_EX_WINDOWEDGE
;
1309 exStyle
&= ~WS_EX_CLIENTEDGE
;
1314 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
) {
1315 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1317 LONG style
, exStyle
;
1318 /* Don't do anything if an original style is stored.
1319 * That shouldn't happen
1321 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1322 if (This
->style
|| This
->exStyle
) {
1323 ERR("(%p): Want to change the window parameters of HWND %p, but "
1324 "another style is stored for restoration afterwards\n", This
, window
);
1327 /* Get the parameters and save them */
1328 style
= GetWindowLongW(window
, GWL_STYLE
);
1329 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1330 This
->style
= style
;
1331 This
->exStyle
= exStyle
;
1333 style
= fullscreen_style(style
);
1334 exStyle
= fullscreen_exStyle(exStyle
);
1336 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1337 This
->style
, This
->exStyle
, style
, exStyle
);
1339 SetWindowLongW(window
, GWL_STYLE
, style
);
1340 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1342 /* Inform the window about the update. */
1343 SetWindowPos(window
, HWND_TOP
, 0, 0,
1344 w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
);
1347 /*****************************************************************************
1348 * IWineD3DDeviceImpl_RestoreWindow
1350 * Helper function that restores a windows' properties when taking it out
1351 * of fullscreen mode
1354 * iface: Pointer to the IWineD3DDevice interface
1355 * window: Window to setup
1357 *****************************************************************************/
1358 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1360 LONG style
, exStyle
;
1362 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1363 * switch, do nothing
1365 if (!This
->style
&& !This
->exStyle
) return;
1367 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1368 This
, window
, This
->style
, This
->exStyle
);
1370 style
= GetWindowLongW(window
, GWL_STYLE
);
1371 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1373 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1374 * Some applications change it before calling Reset() when switching between windowed and
1375 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1377 if(style
== fullscreen_style(This
->style
) &&
1378 exStyle
== fullscreen_style(This
->exStyle
)) {
1379 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1380 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1383 /* Delete the old values */
1387 /* Inform the window about the update */
1388 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1389 0, 0, 0, 0, /* Pos, Size, ignored */
1390 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1393 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1394 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1396 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1397 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
,
1398 WINED3DSURFTYPE surface_type
) {
1399 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1402 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1404 IUnknown
*bufferParent
;
1405 BOOL displaymode_set
= FALSE
;
1406 WINED3DDISPLAYMODE Mode
;
1407 const StaticPixelFormatDesc
*formatDesc
;
1409 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1411 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1412 * does a device hold a reference to a swap chain giving them a lifetime of the device
1413 * or does the swap chain notify the device of its destruction.
1414 *******************************/
1416 /* Check the params */
1417 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1418 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1419 return WINED3DERR_INVALIDCALL
;
1420 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1421 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");
1424 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1425 switch(surface_type
) {
1427 object
->lpVtbl
= &IWineGDISwapChain_Vtbl
;
1429 case SURFACE_OPENGL
:
1430 object
->lpVtbl
= &IWineD3DSwapChain_Vtbl
;
1432 case SURFACE_UNKNOWN
:
1433 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1434 return WINED3DERR_INVALIDCALL
;
1437 /*********************
1438 * Lookup the window Handle and the relating X window handle
1439 ********************/
1441 /* Setup hwnd we are using, plus which display this equates to */
1442 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1443 if (!object
->win_handle
) {
1444 object
->win_handle
= This
->createParms
.hFocusWindow
;
1446 if(!pPresentationParameters
->Windowed
&& object
->win_handle
) {
1447 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
,
1448 pPresentationParameters
->BackBufferWidth
,
1449 pPresentationParameters
->BackBufferHeight
);
1452 hDc
= GetDC(object
->win_handle
);
1453 TRACE("Using hDc %p\n", hDc
);
1456 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1457 return WINED3DERR_NOTAVAILABLE
;
1460 /* Get info on the current display setup */
1461 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1462 object
->orig_width
= Mode
.Width
;
1463 object
->orig_height
= Mode
.Height
;
1464 object
->orig_fmt
= Mode
.Format
;
1465 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1467 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1468 * then the corresponding dimension of the client area of the hDeviceWindow
1469 * (or the focus window, if hDeviceWindow is NULL) is taken.
1470 **********************/
1472 if (pPresentationParameters
->Windowed
&&
1473 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1474 (pPresentationParameters
->BackBufferHeight
== 0) ||
1475 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1478 GetClientRect(object
->win_handle
, &Rect
);
1480 if (pPresentationParameters
->BackBufferWidth
== 0) {
1481 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1482 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1484 if (pPresentationParameters
->BackBufferHeight
== 0) {
1485 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1486 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1488 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1489 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1490 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1494 /* Put the correct figures in the presentation parameters */
1495 TRACE("Copying across presentation parameters\n");
1496 object
->presentParms
= *pPresentationParameters
;
1498 TRACE("calling rendertarget CB\n");
1499 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1501 object
->presentParms
.BackBufferWidth
,
1502 object
->presentParms
.BackBufferHeight
,
1503 object
->presentParms
.BackBufferFormat
,
1504 object
->presentParms
.MultiSampleType
,
1505 object
->presentParms
.MultiSampleQuality
,
1506 TRUE
/* Lockable */,
1507 &object
->frontBuffer
,
1508 NULL
/* pShared (always null)*/);
1509 if (SUCCEEDED(hr
)) {
1510 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1511 if(surface_type
== SURFACE_OPENGL
) {
1512 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1515 ERR("Failed to create the front buffer\n");
1519 /*********************
1520 * Windowed / Fullscreen
1521 *******************/
1524 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1525 * so we should really check to see if there is a fullscreen swapchain already
1526 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1527 **************************************/
1529 if (!pPresentationParameters
->Windowed
) {
1530 WINED3DDISPLAYMODE mode
;
1533 /* Change the display settings */
1534 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1535 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1536 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1537 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1539 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1540 displaymode_set
= TRUE
;
1544 * Create an opengl context for the display visual
1545 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1546 * use different properties after that point in time. FIXME: How to handle when requested format
1547 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1548 * it chooses is identical to the one already being used!
1549 **********************************/
1550 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1552 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1553 if(!object
->context
)
1554 return E_OUTOFMEMORY
;
1555 object
->num_contexts
= 1;
1557 if(surface_type
== SURFACE_OPENGL
) {
1558 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1559 if (!object
->context
[0]) {
1560 ERR("Failed to create a new context\n");
1561 hr
= WINED3DERR_NOTAVAILABLE
;
1564 TRACE("Context created (HWND=%p, glContext=%p)\n",
1565 object
->win_handle
, object
->context
[0]->glCtx
);
1569 /*********************
1570 * Create the back, front and stencil buffers
1571 *******************/
1572 if(object
->presentParms
.BackBufferCount
> 0) {
1575 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1576 if(!object
->backBuffer
) {
1577 ERR("Out of memory\n");
1582 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1583 TRACE("calling rendertarget CB\n");
1584 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1586 object
->presentParms
.BackBufferWidth
,
1587 object
->presentParms
.BackBufferHeight
,
1588 object
->presentParms
.BackBufferFormat
,
1589 object
->presentParms
.MultiSampleType
,
1590 object
->presentParms
.MultiSampleQuality
,
1591 TRUE
/* Lockable */,
1592 &object
->backBuffer
[i
],
1593 NULL
/* pShared (always null)*/);
1595 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1597 ERR("Cannot create new back buffer\n");
1600 if(surface_type
== SURFACE_OPENGL
) {
1602 glDrawBuffer(GL_BACK
);
1603 checkGLcall("glDrawBuffer(GL_BACK)");
1608 object
->backBuffer
= NULL
;
1610 /* Single buffering - draw to front buffer */
1611 if(surface_type
== SURFACE_OPENGL
) {
1613 glDrawBuffer(GL_FRONT
);
1614 checkGLcall("glDrawBuffer(GL_FRONT)");
1619 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1620 if (pPresentationParameters
->EnableAutoDepthStencil
&& surface_type
== SURFACE_OPENGL
) {
1621 TRACE("Creating depth stencil buffer\n");
1622 if (This
->auto_depth_stencil_buffer
== NULL
) {
1623 hr
= D3DCB_CreateDepthStencil(This
->parent
,
1625 object
->presentParms
.BackBufferWidth
,
1626 object
->presentParms
.BackBufferHeight
,
1627 object
->presentParms
.AutoDepthStencilFormat
,
1628 object
->presentParms
.MultiSampleType
,
1629 object
->presentParms
.MultiSampleQuality
,
1630 FALSE
/* FIXME: Discard */,
1631 &This
->auto_depth_stencil_buffer
,
1632 NULL
/* pShared (always null)*/ );
1633 if (SUCCEEDED(hr
)) {
1634 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1636 ERR("Failed to create the auto depth stencil\n");
1642 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1644 TRACE("Created swapchain %p\n", object
);
1645 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, pPresentationParameters
->EnableAutoDepthStencil
);
1649 if (displaymode_set
) {
1653 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1656 /* Change the display settings */
1657 memset(&devmode
, 0, sizeof(devmode
));
1658 devmode
.dmSize
= sizeof(devmode
);
1659 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1660 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1661 devmode
.dmPelsWidth
= object
->orig_width
;
1662 devmode
.dmPelsHeight
= object
->orig_height
;
1663 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1666 if (object
->backBuffer
) {
1668 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1669 if(object
->backBuffer
[i
]) {
1670 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1671 IUnknown_Release(bufferParent
); /* once for the get parent */
1672 if (IUnknown_Release(bufferParent
) > 0) {
1673 FIXME("(%p) Something's still holding the back buffer\n",This
);
1677 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1678 object
->backBuffer
= NULL
;
1680 if(object
->context
[0])
1681 DestroyContext(This
, object
->context
[0]);
1682 if(object
->frontBuffer
) {
1683 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1684 IUnknown_Release(bufferParent
); /* once for the get parent */
1685 if (IUnknown_Release(bufferParent
) > 0) {
1686 FIXME("(%p) Something's still holding the front buffer\n",This
);
1689 HeapFree(GetProcessHeap(), 0, object
);
1693 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1694 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1695 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1696 TRACE("(%p)\n", This
);
1698 return This
->NumberOfSwapChains
;
1701 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1702 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1703 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1705 if(iSwapChain
< This
->NumberOfSwapChains
) {
1706 *pSwapChain
= This
->swapchains
[iSwapChain
];
1707 IWineD3DSwapChain_AddRef(*pSwapChain
);
1708 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1711 TRACE("Swapchain out of range\n");
1713 return WINED3DERR_INVALIDCALL
;
1718 * Vertex Declaration
1720 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1721 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
1722 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1723 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1724 HRESULT hr
= WINED3D_OK
;
1726 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1727 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1729 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1731 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1733 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration
*)object
);
1734 *ppVertexDeclaration
= NULL
;
1740 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1741 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1743 unsigned int idx
, idx2
;
1744 unsigned int offset
;
1745 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1746 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1747 BOOL has_blend_idx
= has_blend
&&
1748 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1749 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1750 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1751 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1752 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1753 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1754 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1756 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1757 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1759 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1760 WINED3DVERTEXELEMENT
*elements
= NULL
;
1763 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1764 if (has_blend_idx
) num_blends
--;
1766 /* Compute declaration size */
1767 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1768 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1770 /* convert the declaration */
1771 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1775 elements
[size
-1] = end_element
;
1778 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1779 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1780 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1783 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1784 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1786 elements
[idx
].UsageIndex
= 0;
1789 if (has_blend
&& (num_blends
> 0)) {
1790 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1791 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1793 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1794 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1795 elements
[idx
].UsageIndex
= 0;
1798 if (has_blend_idx
) {
1799 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1800 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1801 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1802 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1803 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1805 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1806 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1807 elements
[idx
].UsageIndex
= 0;
1811 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1812 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1813 elements
[idx
].UsageIndex
= 0;
1817 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1818 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1819 elements
[idx
].UsageIndex
= 0;
1823 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1824 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1825 elements
[idx
].UsageIndex
= 0;
1829 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1830 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1831 elements
[idx
].UsageIndex
= 1;
1834 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1835 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1836 switch (numcoords
) {
1837 case WINED3DFVF_TEXTUREFORMAT1
:
1838 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1840 case WINED3DFVF_TEXTUREFORMAT2
:
1841 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1843 case WINED3DFVF_TEXTUREFORMAT3
:
1844 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1846 case WINED3DFVF_TEXTUREFORMAT4
:
1847 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1850 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1851 elements
[idx
].UsageIndex
= idx2
;
1855 /* Now compute offsets, and initialize the rest of the fields */
1856 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1857 elements
[idx
].Stream
= 0;
1858 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1859 elements
[idx
].Offset
= offset
;
1860 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1863 *ppVertexElements
= elements
;
1867 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1868 WINED3DVERTEXELEMENT
* elements
= NULL
;
1869 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1873 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1874 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1876 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1877 HeapFree(GetProcessHeap(), 0, elements
);
1878 if (hr
!= S_OK
) return hr
;
1883 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1884 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1885 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1886 HRESULT hr
= WINED3D_OK
;
1887 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1888 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1890 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1892 if (vertex_declaration
) {
1893 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1896 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1898 if (WINED3D_OK
!= hr
) {
1899 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1900 IWineD3DVertexShader_Release(*ppVertexShader
);
1901 return WINED3DERR_INVALIDCALL
;
1903 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1908 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1909 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1910 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1911 HRESULT hr
= WINED3D_OK
;
1913 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1914 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1915 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1916 if (WINED3D_OK
== hr
) {
1917 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1918 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1920 WARN("(%p) : Failed to create pixel shader\n", This
);
1926 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1927 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1928 IWineD3DPaletteImpl
*object
;
1930 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1932 /* Create the new object */
1933 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1935 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1936 return E_OUTOFMEMORY
;
1939 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1941 object
->Flags
= Flags
;
1942 object
->parent
= Parent
;
1943 object
->wineD3DDevice
= This
;
1944 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1946 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1949 HeapFree( GetProcessHeap(), 0, object
);
1950 return E_OUTOFMEMORY
;
1953 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1955 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1959 *Palette
= (IWineD3DPalette
*) object
;
1964 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1968 HDC dcb
= NULL
, dcs
= NULL
;
1969 WINEDDCOLORKEY colorkey
;
1971 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1974 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1975 dcb
= CreateCompatibleDC(NULL
);
1977 SelectObject(dcb
, hbm
);
1981 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1982 * couldn't be loaded
1984 memset(&bm
, 0, sizeof(bm
));
1989 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1990 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1991 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1993 ERR("Wine logo requested, but failed to create surface\n");
1998 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1999 if(FAILED(hr
)) goto out
;
2000 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
2001 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
2003 colorkey
.dwColorSpaceLowValue
= 0;
2004 colorkey
.dwColorSpaceHighValue
= 0;
2005 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
2007 /* Fill the surface with a white color to show that wined3d is there */
2008 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2021 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
2023 /* Under DirectX you can have texture stage operations even if no texture is
2024 bound, whereas opengl will only do texture operations when a valid texture is
2025 bound. We emulate this by creating dummy textures and binding them to each
2026 texture stage, but disable all stages by default. Hence if a stage is enabled
2027 then the default texture will kick in until replaced by a SetTexture call */
2030 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2031 /* The dummy texture does not have client storage backing */
2032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2035 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2036 GLubyte white
= 255;
2038 /* Make appropriate texture active */
2039 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2040 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2041 checkGLcall("glActiveTextureARB");
2043 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2046 /* Generate an opengl texture name */
2047 glGenTextures(1, &This
->dummyTextureName
[i
]);
2048 checkGLcall("glGenTextures");
2049 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2051 /* Generate a dummy 2d texture (not using 1d because they cause many
2052 * DRI drivers fall back to sw) */
2053 This
->stateBlock
->textureDimensions
[i
] = GL_TEXTURE_2D
;
2054 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2055 checkGLcall("glBindTexture");
2057 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2058 checkGLcall("glTexImage2D");
2060 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2061 /* Reenable because if supported it is enabled by default */
2062 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2063 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2069 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2070 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2071 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2076 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
2077 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2078 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2080 /* TODO: Test if OpenGL is compiled in and loaded */
2082 TRACE("(%p) : Creating stateblock\n", This
);
2083 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2084 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2086 (IWineD3DStateBlock
**)&This
->stateBlock
,
2088 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2089 WARN("Failed to create stateblock\n");
2092 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2093 This
->updateStateBlock
= This
->stateBlock
;
2094 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2096 hr
= allocate_shader_constants(This
->updateStateBlock
);
2097 if (WINED3D_OK
!= hr
) {
2101 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2102 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2104 This
->NumberOfPalettes
= 1;
2105 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
2106 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
2107 ERR("Out of memory!\n");
2110 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2111 if(!This
->palettes
[0]) {
2112 ERR("Out of memory!\n");
2115 for (i
= 0; i
< 256; ++i
) {
2116 This
->palettes
[0][i
].peRed
= 0xFF;
2117 This
->palettes
[0][i
].peGreen
= 0xFF;
2118 This
->palettes
[0][i
].peBlue
= 0xFF;
2119 This
->palettes
[0][i
].peFlags
= 0xFF;
2121 This
->currentPalette
= 0;
2123 /* Initialize the texture unit mapping to a 1:1 mapping */
2124 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2125 if (state
< GL_LIMITS(fragment_samplers
)) {
2126 This
->texUnitMap
[state
] = state
;
2127 This
->rev_tex_unit_map
[state
] = state
;
2129 This
->texUnitMap
[state
] = -1;
2130 This
->rev_tex_unit_map
[state
] = -1;
2134 /* Setup the implicit swapchain */
2135 TRACE("Creating implicit swapchain\n");
2136 hr
=D3DCB_CreateAdditionalSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2137 if (FAILED(hr
) || !swapchain
) {
2138 WARN("Failed to create implicit swapchain\n");
2142 This
->NumberOfSwapChains
= 1;
2143 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2144 if(!This
->swapchains
) {
2145 ERR("Out of memory!\n");
2148 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2150 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2151 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2152 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2153 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2156 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2157 This
->render_targets
[0] = swapchain
->frontBuffer
;
2158 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2160 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2161 This
->activeContext
= swapchain
->context
[0];
2162 This
->lastThread
= GetCurrentThreadId();
2164 /* Depth Stencil support */
2165 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2166 if (NULL
!= This
->stencilBufferTarget
) {
2167 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2170 hr
= This
->shader_backend
->shader_alloc_private(iface
);
2172 TRACE("Shader private data couldn't be allocated\n");
2175 hr
= This
->frag_pipe
->alloc_private(iface
);
2177 TRACE("Fragment pipeline private data couldn't be allocated\n");
2180 hr
= This
->blitter
->alloc_private(iface
);
2182 TRACE("Blitter private data couldn't be allocated\n");
2186 /* Set up some starting GL setup */
2188 /* Setup all the devices defaults */
2189 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2190 create_dummy_textures(This
);
2194 { /* Set a default viewport */
2198 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2199 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2202 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2205 /* Initialize the current view state */
2206 This
->view_ident
= 1;
2207 This
->contexts
[0]->last_was_rhw
= 0;
2208 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2209 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2211 switch(wined3d_settings
.offscreen_rendering_mode
) {
2214 This
->offscreenBuffer
= GL_BACK
;
2217 case ORM_BACKBUFFER
:
2219 if(This
->activeContext
->aux_buffers
> 0) {
2220 TRACE("Using auxilliary buffer for offscreen rendering\n");
2221 This
->offscreenBuffer
= GL_AUX0
;
2223 TRACE("Using back buffer for offscreen rendering\n");
2224 This
->offscreenBuffer
= GL_BACK
;
2229 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2232 /* Clear the screen */
2233 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2234 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2237 This
->d3d_initialized
= TRUE
;
2239 if(wined3d_settings
.logo
) {
2240 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2242 This
->highest_dirty_ps_const
= 0;
2243 This
->highest_dirty_vs_const
= 0;
2247 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2248 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2249 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2250 This
->NumberOfSwapChains
= 0;
2251 if(This
->palettes
) {
2252 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2253 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2255 This
->NumberOfPalettes
= 0;
2257 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2259 if(This
->stateBlock
) {
2260 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2261 This
->stateBlock
= NULL
;
2263 if (This
->blit_priv
) {
2264 This
->blitter
->free_private(iface
);
2266 if (This
->fragment_priv
) {
2267 This
->frag_pipe
->free_private(iface
);
2269 if (This
->shader_priv
) {
2270 This
->shader_backend
->shader_free_private(iface
);
2275 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2277 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2280 /* Setup the implicit swapchain */
2281 TRACE("Creating implicit swapchain\n");
2282 hr
=D3DCB_CreateAdditionalSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2283 if (FAILED(hr
) || !swapchain
) {
2284 WARN("Failed to create implicit swapchain\n");
2288 This
->NumberOfSwapChains
= 1;
2289 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2290 if(!This
->swapchains
) {
2291 ERR("Out of memory!\n");
2294 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2298 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2302 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2306 TRACE("(%p)\n", This
);
2308 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2310 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2311 * it was created. Thus make sure a context is active for the glDelete* calls
2313 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2315 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2317 TRACE("Deleting high order patches\n");
2318 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2319 struct list
*e1
, *e2
;
2320 struct WineD3DRectPatch
*patch
;
2321 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2322 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2323 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2327 /* Delete the palette conversion shader if it is around */
2328 if(This
->paletteConversionShader
) {
2330 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2332 This
->paletteConversionShader
= 0;
2335 /* Delete the pbuffer context if there is any */
2336 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2338 /* Delete the mouse cursor texture */
2339 if(This
->cursorTexture
) {
2341 glDeleteTextures(1, &This
->cursorTexture
);
2343 This
->cursorTexture
= 0;
2346 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2347 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2349 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2350 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2353 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2354 * private data, it might contain opengl pointers
2356 if(This
->depth_blt_texture
) {
2357 glDeleteTextures(1, &This
->depth_blt_texture
);
2358 This
->depth_blt_texture
= 0;
2360 if (This
->depth_blt_rb
) {
2361 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2362 This
->depth_blt_rb
= 0;
2363 This
->depth_blt_rb_w
= 0;
2364 This
->depth_blt_rb_h
= 0;
2367 /* Release the update stateblock */
2368 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2369 if(This
->updateStateBlock
!= This
->stateBlock
)
2370 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2372 This
->updateStateBlock
= NULL
;
2374 { /* because were not doing proper internal refcounts releasing the primary state block
2375 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2376 to set this->stateBlock = NULL; first */
2377 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2378 This
->stateBlock
= NULL
;
2380 /* Release the stateblock */
2381 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2382 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2386 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2387 This
->blitter
->free_private(iface
);
2388 This
->frag_pipe
->free_private(iface
);
2389 This
->shader_backend
->shader_free_private(iface
);
2391 /* Release the buffers (with sanity checks)*/
2392 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2393 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2394 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2395 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2397 This
->stencilBufferTarget
= NULL
;
2399 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2400 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2401 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2403 TRACE("Setting rendertarget to NULL\n");
2404 This
->render_targets
[0] = NULL
;
2406 if (This
->auto_depth_stencil_buffer
) {
2407 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2408 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2410 This
->auto_depth_stencil_buffer
= NULL
;
2413 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2414 TRACE("Releasing the implicit swapchain %d\n", i
);
2415 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2416 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2420 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2421 This
->swapchains
= NULL
;
2422 This
->NumberOfSwapChains
= 0;
2424 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2425 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2426 This
->palettes
= NULL
;
2427 This
->NumberOfPalettes
= 0;
2429 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2430 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2431 This
->render_targets
= NULL
;
2432 This
->draw_buffers
= NULL
;
2434 This
->d3d_initialized
= FALSE
;
2438 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2439 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2442 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2443 TRACE("Releasing the implicit swapchain %d\n", i
);
2444 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2445 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2449 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2450 This
->swapchains
= NULL
;
2451 This
->NumberOfSwapChains
= 0;
2455 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2456 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2457 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2459 * There is no way to deactivate thread safety once it is enabled.
2461 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2462 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2464 /*For now just store the flag(needed in case of ddraw) */
2465 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2470 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2472 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2474 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2477 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2479 /* Resize the screen even without a window:
2480 * The app could have unset it with SetCooperativeLevel, but not called
2481 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2482 * but we don't have any hwnd
2485 memset(&devmode
, 0, sizeof(devmode
));
2486 devmode
.dmSize
= sizeof(devmode
);
2487 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2488 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2489 devmode
.dmPelsWidth
= pMode
->Width
;
2490 devmode
.dmPelsHeight
= pMode
->Height
;
2492 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2493 if (pMode
->RefreshRate
!= 0) {
2494 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2497 /* Only change the mode if necessary */
2498 if( (This
->ddraw_width
== pMode
->Width
) &&
2499 (This
->ddraw_height
== pMode
->Height
) &&
2500 (This
->ddraw_format
== pMode
->Format
) &&
2501 (pMode
->RefreshRate
== 0) ) {
2505 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2506 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2507 if(devmode
.dmDisplayFrequency
!= 0) {
2508 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2509 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2510 devmode
.dmDisplayFrequency
= 0;
2511 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2513 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2514 return WINED3DERR_NOTAVAILABLE
;
2518 /* Store the new values */
2519 This
->ddraw_width
= pMode
->Width
;
2520 This
->ddraw_height
= pMode
->Height
;
2521 This
->ddraw_format
= pMode
->Format
;
2523 /* And finally clip mouse to our screen */
2524 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2525 ClipCursor(&clip_rc
);
2530 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2531 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2532 *ppD3D
= This
->wineD3D
;
2533 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2534 IWineD3D_AddRef(*ppD3D
);
2538 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2539 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2541 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2542 (This
->adapter
->TextureRam
/(1024*1024)),
2543 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2544 /* return simulated texture memory left */
2545 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2553 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2554 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2556 /* Update the current state block */
2557 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2559 if(This
->updateStateBlock
->fvf
== fvf
) {
2560 TRACE("Application is setting the old fvf over, nothing to do\n");
2564 This
->updateStateBlock
->fvf
= fvf
;
2565 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2566 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2571 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2572 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2573 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2574 *pfvf
= This
->stateBlock
->fvf
;
2579 * Get / Set Stream Source
2581 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2583 IWineD3DVertexBuffer
*oldSrc
;
2585 if (StreamNumber
>= MAX_STREAMS
) {
2586 WARN("Stream out of range %d\n", StreamNumber
);
2587 return WINED3DERR_INVALIDCALL
;
2588 } else if(OffsetInBytes
& 0x3) {
2589 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2590 return WINED3DERR_INVALIDCALL
;
2593 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2594 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2596 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2598 if(oldSrc
== pStreamData
&&
2599 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2600 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2601 TRACE("Application is setting the old values over, nothing to do\n");
2605 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2607 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2608 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2611 /* Handle recording of state blocks */
2612 if (This
->isRecordingState
) {
2613 TRACE("Recording... not performing anything\n");
2614 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2615 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2619 /* Need to do a getParent and pass the references up */
2620 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2621 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2622 so for now, just count internally */
2623 if (pStreamData
!= NULL
) {
2624 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2625 InterlockedIncrement(&vbImpl
->bindCount
);
2626 IWineD3DVertexBuffer_AddRef(pStreamData
);
2628 if (oldSrc
!= NULL
) {
2629 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2630 IWineD3DVertexBuffer_Release(oldSrc
);
2633 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2638 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2639 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2641 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2642 This
->stateBlock
->streamSource
[StreamNumber
],
2643 This
->stateBlock
->streamOffset
[StreamNumber
],
2644 This
->stateBlock
->streamStride
[StreamNumber
]);
2646 if (StreamNumber
>= MAX_STREAMS
) {
2647 WARN("Stream out of range %d\n", StreamNumber
);
2648 return WINED3DERR_INVALIDCALL
;
2650 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2651 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2653 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2656 if (*pStream
!= NULL
) {
2657 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2662 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2663 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2664 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2665 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2667 /* Verify input at least in d3d9 this is invalid*/
2668 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2669 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2670 return WINED3DERR_INVALIDCALL
;
2672 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2673 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2674 return WINED3DERR_INVALIDCALL
;
2677 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2678 return WINED3DERR_INVALIDCALL
;
2681 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2682 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2684 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2685 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2687 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2688 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2689 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2695 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2696 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2698 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2699 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2701 TRACE("(%p) : returning %d\n", This
, *Divider
);
2707 * Get / Set & Multiply Transform
2709 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2710 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2712 /* Most of this routine, comments included copied from ddraw tree initially: */
2713 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2715 /* Handle recording of state blocks */
2716 if (This
->isRecordingState
) {
2717 TRACE("Recording... not performing anything\n");
2718 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2719 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2724 * If the new matrix is the same as the current one,
2725 * we cut off any further processing. this seems to be a reasonable
2726 * optimization because as was noticed, some apps (warcraft3 for example)
2727 * tend towards setting the same matrix repeatedly for some reason.
2729 * From here on we assume that the new matrix is different, wherever it matters.
2731 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2732 TRACE("The app is setting the same matrix over again\n");
2735 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2739 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2740 where ViewMat = Camera space, WorldMat = world space.
2742 In OpenGL, camera and world space is combined into GL_MODELVIEW
2743 matrix. The Projection matrix stay projection matrix.
2746 /* Capture the times we can just ignore the change for now */
2747 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2748 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2749 /* Handled by the state manager */
2752 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2756 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2757 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2758 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2759 *pMatrix
= This
->stateBlock
->transforms
[State
];
2763 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2764 WINED3DMATRIX
*mat
= NULL
;
2767 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2768 * below means it will be recorded in a state block change, but it
2769 * works regardless where it is recorded.
2770 * If this is found to be wrong, change to StateBlock.
2772 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2773 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2775 if (State
< HIGHEST_TRANSFORMSTATE
)
2777 mat
= &This
->updateStateBlock
->transforms
[State
];
2779 FIXME("Unhandled transform state!!\n");
2782 multiply_matrix(&temp
, mat
, pMatrix
);
2784 /* Apply change via set transform - will reapply to eg. lights this way */
2785 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2791 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2792 you can reference any indexes you want as long as that number max are enabled at any
2793 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2794 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2795 but when recording, just build a chain pretty much of commands to be replayed. */
2797 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2799 PLIGHTINFOEL
*object
= NULL
;
2800 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2803 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2804 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2806 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2810 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2811 return WINED3DERR_INVALIDCALL
;
2814 switch(pLight
->Type
) {
2815 case WINED3DLIGHT_POINT
:
2816 case WINED3DLIGHT_SPOT
:
2817 case WINED3DLIGHT_PARALLELPOINT
:
2818 case WINED3DLIGHT_GLSPOT
:
2819 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2822 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2823 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2824 return WINED3DERR_INVALIDCALL
;
2828 case WINED3DLIGHT_DIRECTIONAL
:
2829 /* Ignores attenuation */
2833 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2834 return WINED3DERR_INVALIDCALL
;
2837 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2838 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2839 if(object
->OriginalIndex
== Index
) break;
2844 TRACE("Adding new light\n");
2845 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2847 ERR("Out of memory error when allocating a light\n");
2848 return E_OUTOFMEMORY
;
2850 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2851 object
->glIndex
= -1;
2852 object
->OriginalIndex
= Index
;
2853 object
->changed
= TRUE
;
2856 /* Initialize the object */
2857 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
,
2858 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2859 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2860 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2861 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2862 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2863 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2865 /* Save away the information */
2866 object
->OriginalParms
= *pLight
;
2868 switch (pLight
->Type
) {
2869 case WINED3DLIGHT_POINT
:
2871 object
->lightPosn
[0] = pLight
->Position
.x
;
2872 object
->lightPosn
[1] = pLight
->Position
.y
;
2873 object
->lightPosn
[2] = pLight
->Position
.z
;
2874 object
->lightPosn
[3] = 1.0f
;
2875 object
->cutoff
= 180.0f
;
2879 case WINED3DLIGHT_DIRECTIONAL
:
2881 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2882 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2883 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2884 object
->lightPosn
[3] = 0.0;
2885 object
->exponent
= 0.0f
;
2886 object
->cutoff
= 180.0f
;
2889 case WINED3DLIGHT_SPOT
:
2891 object
->lightPosn
[0] = pLight
->Position
.x
;
2892 object
->lightPosn
[1] = pLight
->Position
.y
;
2893 object
->lightPosn
[2] = pLight
->Position
.z
;
2894 object
->lightPosn
[3] = 1.0;
2897 object
->lightDirn
[0] = pLight
->Direction
.x
;
2898 object
->lightDirn
[1] = pLight
->Direction
.y
;
2899 object
->lightDirn
[2] = pLight
->Direction
.z
;
2900 object
->lightDirn
[3] = 1.0;
2903 * opengl-ish and d3d-ish spot lights use too different models for the
2904 * light "intensity" as a function of the angle towards the main light direction,
2905 * so we only can approximate very roughly.
2906 * however spot lights are rather rarely used in games (if ever used at all).
2907 * furthermore if still used, probably nobody pays attention to such details.
2909 if (pLight
->Falloff
== 0) {
2910 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2911 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2912 * will always be 1.0 for both of them, and we don't have to care for the
2913 * rest of the rather complex calculation
2915 object
->exponent
= 0;
2917 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2918 if (rho
< 0.0001) rho
= 0.0001f
;
2919 object
->exponent
= -0.3/log(cos(rho
/2));
2921 if (object
->exponent
> 128.0) {
2922 object
->exponent
= 128.0;
2924 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2930 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2933 /* Update the live definitions if the light is currently assigned a glIndex */
2934 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2935 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2940 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2941 PLIGHTINFOEL
*lightInfo
= NULL
;
2942 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2943 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2945 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2947 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2948 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2949 if(lightInfo
->OriginalIndex
== Index
) break;
2953 if (lightInfo
== NULL
) {
2954 TRACE("Light information requested but light not defined\n");
2955 return WINED3DERR_INVALIDCALL
;
2958 *pLight
= lightInfo
->OriginalParms
;
2963 * Get / Set Light Enable
2964 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2966 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2967 PLIGHTINFOEL
*lightInfo
= NULL
;
2968 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2969 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2971 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2973 /* Tests show true = 128...not clear why */
2974 Enable
= Enable
? 128: 0;
2976 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2977 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2978 if(lightInfo
->OriginalIndex
== Index
) break;
2981 TRACE("Found light: %p\n", lightInfo
);
2983 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2984 if (lightInfo
== NULL
) {
2986 TRACE("Light enabled requested but light not defined, so defining one!\n");
2987 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2989 /* Search for it again! Should be fairly quick as near head of list */
2990 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2991 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2992 if(lightInfo
->OriginalIndex
== Index
) break;
2995 if (lightInfo
== NULL
) {
2996 FIXME("Adding default lights has failed dismally\n");
2997 return WINED3DERR_INVALIDCALL
;
3001 lightInfo
->enabledChanged
= TRUE
;
3003 if(lightInfo
->glIndex
!= -1) {
3004 if(!This
->isRecordingState
) {
3005 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
3008 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
3009 lightInfo
->glIndex
= -1;
3011 TRACE("Light already disabled, nothing to do\n");
3013 lightInfo
->enabled
= FALSE
;
3015 lightInfo
->enabled
= TRUE
;
3016 if (lightInfo
->glIndex
!= -1) {
3018 TRACE("Nothing to do as light was enabled\n");
3021 /* Find a free gl light */
3022 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
3023 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
3024 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
3025 lightInfo
->glIndex
= i
;
3029 if(lightInfo
->glIndex
== -1) {
3030 /* Our tests show that Windows returns D3D_OK in this situation, even with
3031 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3032 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3033 * as well for those lights.
3035 * TODO: Test how this affects rendering
3037 FIXME("Too many concurrently active lights\n");
3041 /* i == lightInfo->glIndex */
3042 if(!This
->isRecordingState
) {
3043 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
3051 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
3053 PLIGHTINFOEL
*lightInfo
= NULL
;
3054 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3056 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3057 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3059 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3060 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3061 if(lightInfo
->OriginalIndex
== Index
) break;
3065 if (lightInfo
== NULL
) {
3066 TRACE("Light enabled state requested but light not defined\n");
3067 return WINED3DERR_INVALIDCALL
;
3069 /* true is 128 according to SetLightEnable */
3070 *pEnable
= lightInfo
->enabled
? 128 : 0;
3075 * Get / Set Clip Planes
3077 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3078 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3079 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3081 /* Validate Index */
3082 if (Index
>= GL_LIMITS(clipplanes
)) {
3083 TRACE("Application has requested clipplane this device doesn't support\n");
3084 return WINED3DERR_INVALIDCALL
;
3087 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
3089 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3090 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3091 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3092 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3093 TRACE("Application is setting old values over, nothing to do\n");
3097 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3098 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3099 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3100 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3102 /* Handle recording of state blocks */
3103 if (This
->isRecordingState
) {
3104 TRACE("Recording... not performing anything\n");
3108 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3113 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3114 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3115 TRACE("(%p) : for idx %d\n", This
, Index
);
3117 /* Validate Index */
3118 if (Index
>= GL_LIMITS(clipplanes
)) {
3119 TRACE("Application has requested clipplane this device doesn't support\n");
3120 return WINED3DERR_INVALIDCALL
;
3123 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3124 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3125 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3126 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3131 * Get / Set Clip Plane Status
3132 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3134 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3135 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3136 FIXME("(%p) : stub\n", This
);
3137 if (NULL
== pClipStatus
) {
3138 return WINED3DERR_INVALIDCALL
;
3140 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3141 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3145 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3146 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3147 FIXME("(%p) : stub\n", This
);
3148 if (NULL
== pClipStatus
) {
3149 return WINED3DERR_INVALIDCALL
;
3151 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3152 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3157 * Get / Set Material
3159 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3162 This
->updateStateBlock
->changed
.material
= TRUE
;
3163 This
->updateStateBlock
->material
= *pMaterial
;
3165 /* Handle recording of state blocks */
3166 if (This
->isRecordingState
) {
3167 TRACE("Recording... not performing anything\n");
3171 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3175 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3176 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3177 *pMaterial
= This
->updateStateBlock
->material
;
3178 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3179 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3180 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3181 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3182 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3183 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3184 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3185 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3186 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3194 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3195 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3196 IWineD3DIndexBuffer
*oldIdxs
;
3198 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3199 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3201 This
->updateStateBlock
->changed
.indices
= TRUE
;
3202 This
->updateStateBlock
->pIndexData
= pIndexData
;
3204 /* Handle recording of state blocks */
3205 if (This
->isRecordingState
) {
3206 TRACE("Recording... not performing anything\n");
3207 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3208 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3212 if(oldIdxs
!= pIndexData
) {
3213 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3214 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3215 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3220 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3221 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3223 *ppIndexData
= This
->stateBlock
->pIndexData
;
3225 /* up ref count on ppindexdata */
3227 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3228 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3230 TRACE("(%p) No index data set\n", This
);
3232 TRACE("Returning %p\n", *ppIndexData
);
3237 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3238 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3239 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3240 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3242 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3243 TRACE("Application is setting the old value over, nothing to do\n");
3247 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3249 if (This
->isRecordingState
) {
3250 TRACE("Recording... not performing anything\n");
3253 /* The base vertex index affects the stream sources */
3254 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3258 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3259 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3260 TRACE("(%p) : base_index %p\n", This
, base_index
);
3262 *base_index
= This
->stateBlock
->baseVertexIndex
;
3264 TRACE("Returning %u\n", *base_index
);
3270 * Get / Set Viewports
3272 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3273 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3275 TRACE("(%p)\n", This
);
3276 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3277 This
->updateStateBlock
->viewport
= *pViewport
;
3279 /* Handle recording of state blocks */
3280 if (This
->isRecordingState
) {
3281 TRACE("Recording... not performing anything\n");
3285 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3286 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3288 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3293 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3294 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3295 TRACE("(%p)\n", This
);
3296 *pViewport
= This
->stateBlock
->viewport
;
3301 * Get / Set Render States
3302 * TODO: Verify against dx9 definitions
3304 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3306 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3307 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3309 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3311 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3312 This
->updateStateBlock
->renderState
[State
] = Value
;
3314 /* Handle recording of state blocks */
3315 if (This
->isRecordingState
) {
3316 TRACE("Recording... not performing anything\n");
3320 /* Compared here and not before the assignment to allow proper stateblock recording */
3321 if(Value
== oldValue
) {
3322 TRACE("Application is setting the old value over, nothing to do\n");
3324 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3330 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3332 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3333 *pValue
= This
->stateBlock
->renderState
[State
];
3338 * Get / Set Sampler States
3339 * TODO: Verify against dx9 definitions
3342 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3343 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3346 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3347 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3349 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3350 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3353 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3354 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3355 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3358 * SetSampler is designed to allow for more than the standard up to 8 textures
3359 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3360 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3362 * http://developer.nvidia.com/object/General_FAQ.html#t6
3364 * There are two new settings for GForce
3366 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3367 * and the texture one:
3368 * GL_MAX_TEXTURE_COORDS_ARB.
3369 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3372 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3373 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3374 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3376 /* Handle recording of state blocks */
3377 if (This
->isRecordingState
) {
3378 TRACE("Recording... not performing anything\n");
3382 if(oldValue
== Value
) {
3383 TRACE("Application is setting the old value over, nothing to do\n");
3387 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3392 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3395 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3396 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3398 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3399 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3402 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3403 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3404 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3406 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3407 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3412 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3413 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3415 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3416 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3417 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3420 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3422 if(This
->isRecordingState
) {
3423 TRACE("Recording... not performing anything\n");
3427 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3432 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3433 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3435 *pRect
= This
->updateStateBlock
->scissorRect
;
3436 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3440 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3441 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3442 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3444 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3446 This
->updateStateBlock
->vertexDecl
= pDecl
;
3447 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3449 if (This
->isRecordingState
) {
3450 TRACE("Recording... not performing anything\n");
3452 } else if(pDecl
== oldDecl
) {
3453 /* Checked after the assignment to allow proper stateblock recording */
3454 TRACE("Application is setting the old declaration over, nothing to do\n");
3458 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3462 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3463 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3465 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3467 *ppDecl
= This
->stateBlock
->vertexDecl
;
3468 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3472 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3473 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3474 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3476 This
->updateStateBlock
->vertexShader
= pShader
;
3477 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3479 if (This
->isRecordingState
) {
3480 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3481 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3482 TRACE("Recording... not performing anything\n");
3484 } else if(oldShader
== pShader
) {
3485 /* Checked here to allow proper stateblock recording */
3486 TRACE("App is setting the old shader over, nothing to do\n");
3490 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3491 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3492 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3494 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3499 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3500 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3502 if (NULL
== ppShader
) {
3503 return WINED3DERR_INVALIDCALL
;
3505 *ppShader
= This
->stateBlock
->vertexShader
;
3506 if( NULL
!= *ppShader
)
3507 IWineD3DVertexShader_AddRef(*ppShader
);
3509 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3513 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3514 IWineD3DDevice
*iface
,
3516 CONST BOOL
*srcData
,
3519 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3520 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3522 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3523 iface
, srcData
, start
, count
);
3525 if (srcData
== NULL
|| cnt
< 0)
3526 return WINED3DERR_INVALIDCALL
;
3528 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3529 for (i
= 0; i
< cnt
; i
++)
3530 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3532 for (i
= start
; i
< cnt
+ start
; ++i
) {
3533 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3536 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3541 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3542 IWineD3DDevice
*iface
,
3547 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3548 int cnt
= min(count
, MAX_CONST_B
- start
);
3550 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3551 iface
, dstData
, start
, count
);
3553 if (dstData
== NULL
|| cnt
< 0)
3554 return WINED3DERR_INVALIDCALL
;
3556 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3560 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3561 IWineD3DDevice
*iface
,
3566 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3567 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3569 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3570 iface
, srcData
, start
, count
);
3572 if (srcData
== NULL
|| cnt
< 0)
3573 return WINED3DERR_INVALIDCALL
;
3575 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3576 for (i
= 0; i
< cnt
; i
++)
3577 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3578 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3580 for (i
= start
; i
< cnt
+ start
; ++i
) {
3581 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3584 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3589 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3590 IWineD3DDevice
*iface
,
3595 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3596 int cnt
= min(count
, MAX_CONST_I
- start
);
3598 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3599 iface
, dstData
, start
, count
);
3601 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3602 return WINED3DERR_INVALIDCALL
;
3604 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3608 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3609 IWineD3DDevice
*iface
,
3611 CONST
float *srcData
,
3614 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3617 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3618 iface
, srcData
, start
, count
);
3620 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3621 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3622 return WINED3DERR_INVALIDCALL
;
3624 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3626 for (i
= 0; i
< count
; i
++)
3627 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3628 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3631 for (i
= start
; i
< count
+ start
; ++i
) {
3632 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3633 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3634 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3635 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3636 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3638 ptr
->idx
[ptr
->count
++] = i
;
3639 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3643 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3648 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3649 IWineD3DDevice
*iface
,
3651 CONST
float *srcData
,
3654 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3657 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3658 iface
, srcData
, start
, count
);
3660 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3661 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3662 return WINED3DERR_INVALIDCALL
;
3664 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3666 for (i
= 0; i
< count
; i
++)
3667 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3668 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3671 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3672 * context. On a context switch the old context will be fully dirtified
3674 memset(This
->activeContext
->vshader_const_dirty
+ start
, 1,
3675 sizeof(*This
->activeContext
->vshader_const_dirty
) * count
);
3676 This
->highest_dirty_vs_const
= max(This
->highest_dirty_vs_const
, start
+count
+1);
3678 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3683 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3684 IWineD3DDevice
*iface
,
3689 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3690 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3692 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3693 iface
, dstData
, start
, count
);
3695 if (dstData
== NULL
|| cnt
< 0)
3696 return WINED3DERR_INVALIDCALL
;
3698 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3702 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3704 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3705 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3709 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3710 int i
= This
->rev_tex_unit_map
[unit
];
3711 int j
= This
->texUnitMap
[stage
];
3713 This
->texUnitMap
[stage
] = unit
;
3714 if (i
!= -1 && i
!= stage
) {
3715 This
->texUnitMap
[i
] = -1;
3718 This
->rev_tex_unit_map
[unit
] = stage
;
3719 if (j
!= -1 && j
!= unit
) {
3720 This
->rev_tex_unit_map
[j
] = -1;
3724 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3727 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3728 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3729 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3730 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3731 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3732 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3733 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3734 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3735 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3737 if (color_op
== WINED3DTOP_DISABLE
) {
3738 /* Not used, and disable higher stages */
3739 while (i
< MAX_TEXTURES
) {
3740 This
->fixed_function_usage_map
[i
] = FALSE
;
3746 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3747 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3748 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3749 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3750 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3751 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3752 This
->fixed_function_usage_map
[i
] = TRUE
;
3754 This
->fixed_function_usage_map
[i
] = FALSE
;
3757 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3758 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3763 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3766 device_update_fixed_function_usage_map(This
);
3768 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3769 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3770 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3771 if (!This
->fixed_function_usage_map
[i
]) continue;
3773 if (This
->texUnitMap
[i
] != i
) {
3774 device_map_stage(This
, i
, i
);
3775 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3776 markTextureStagesDirty(This
, i
);
3782 /* Now work out the mapping */
3784 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3785 if (!This
->fixed_function_usage_map
[i
]) continue;
3787 if (This
->texUnitMap
[i
] != tex
) {
3788 device_map_stage(This
, i
, tex
);
3789 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3790 markTextureStagesDirty(This
, i
);
3797 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3798 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3801 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3802 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3803 device_map_stage(This
, i
, i
);
3804 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3805 if (i
< MAX_TEXTURES
) {
3806 markTextureStagesDirty(This
, i
);
3812 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3813 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3815 if (current_mapping
== -1) {
3816 /* Not currently used */
3820 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3821 /* Used by a fragment sampler */
3823 if (!pshader_sampler_tokens
) {
3824 /* No pixel shader, check fixed function */
3825 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3828 /* Pixel shader, check the shader's sampler map */
3829 return !pshader_sampler_tokens
[current_mapping
];
3832 /* Used by a vertex sampler */
3833 return !vshader_sampler_tokens
[current_mapping
];
3836 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3837 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3838 DWORD
*pshader_sampler_tokens
= NULL
;
3839 int start
= GL_LIMITS(combined_samplers
) - 1;
3843 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3845 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3846 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3847 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3850 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3851 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3852 if (vshader_sampler_tokens
[i
]) {
3853 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3854 /* Already mapped somewhere */
3858 while (start
>= 0) {
3859 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3860 device_map_stage(This
, vsampler_idx
, start
);
3861 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3873 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3874 BOOL vs
= use_vs(This
);
3875 BOOL ps
= use_ps(This
);
3878 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3879 * that would be really messy and require shader recompilation
3880 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3881 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3884 device_map_psamplers(This
);
3886 device_map_fixed_function_samplers(This
);
3890 device_map_vsamplers(This
, ps
);
3894 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3895 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3896 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3897 This
->updateStateBlock
->pixelShader
= pShader
;
3898 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3900 /* Handle recording of state blocks */
3901 if (This
->isRecordingState
) {
3902 TRACE("Recording... not performing anything\n");
3905 if (This
->isRecordingState
) {
3906 TRACE("Recording... not performing anything\n");
3907 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3908 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3912 if(pShader
== oldShader
) {
3913 TRACE("App is setting the old pixel shader over, nothing to do\n");
3917 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3918 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3920 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3921 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3926 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3927 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3929 if (NULL
== ppShader
) {
3930 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3931 return WINED3DERR_INVALIDCALL
;
3934 *ppShader
= This
->stateBlock
->pixelShader
;
3935 if (NULL
!= *ppShader
) {
3936 IWineD3DPixelShader_AddRef(*ppShader
);
3938 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3942 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3943 IWineD3DDevice
*iface
,
3945 CONST BOOL
*srcData
,
3948 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3949 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3951 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3952 iface
, srcData
, start
, count
);
3954 if (srcData
== NULL
|| cnt
< 0)
3955 return WINED3DERR_INVALIDCALL
;
3957 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3958 for (i
= 0; i
< cnt
; i
++)
3959 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3961 for (i
= start
; i
< cnt
+ start
; ++i
) {
3962 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3965 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3970 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3971 IWineD3DDevice
*iface
,
3976 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3977 int cnt
= min(count
, MAX_CONST_B
- start
);
3979 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3980 iface
, dstData
, start
, count
);
3982 if (dstData
== NULL
|| cnt
< 0)
3983 return WINED3DERR_INVALIDCALL
;
3985 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3989 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3990 IWineD3DDevice
*iface
,
3995 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3996 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3998 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3999 iface
, srcData
, start
, count
);
4001 if (srcData
== NULL
|| cnt
< 0)
4002 return WINED3DERR_INVALIDCALL
;
4004 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
4005 for (i
= 0; i
< cnt
; i
++)
4006 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
4007 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4009 for (i
= start
; i
< cnt
+ start
; ++i
) {
4010 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
4013 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4018 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
4019 IWineD3DDevice
*iface
,
4024 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4025 int cnt
= min(count
, MAX_CONST_I
- start
);
4027 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4028 iface
, dstData
, start
, count
);
4030 if (dstData
== NULL
|| cnt
< 0)
4031 return WINED3DERR_INVALIDCALL
;
4033 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
4037 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
4038 IWineD3DDevice
*iface
,
4040 CONST
float *srcData
,
4043 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4046 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4047 iface
, srcData
, start
, count
);
4049 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4050 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4051 return WINED3DERR_INVALIDCALL
;
4053 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4055 for (i
= 0; i
< count
; i
++)
4056 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4057 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4060 for (i
= start
; i
< count
+ start
; ++i
) {
4061 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
4062 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
4063 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
4064 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
4065 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
4067 ptr
->idx
[ptr
->count
++] = i
;
4068 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
4072 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4077 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4078 IWineD3DDevice
*iface
,
4080 CONST
float *srcData
,
4083 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4086 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4087 iface
, srcData
, start
, count
);
4089 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4090 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4091 return WINED3DERR_INVALIDCALL
;
4093 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4095 for (i
= 0; i
< count
; i
++)
4096 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4097 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4100 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4101 * context. On a context switch the old context will be fully dirtified
4103 memset(This
->activeContext
->pshader_const_dirty
+ start
, 1,
4104 sizeof(*This
->activeContext
->pshader_const_dirty
) * count
);
4105 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, start
+count
+1);
4107 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4112 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
4113 IWineD3DDevice
*iface
,
4118 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4119 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
4121 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4122 iface
, dstData
, start
, count
);
4124 if (dstData
== NULL
|| cnt
< 0)
4125 return WINED3DERR_INVALIDCALL
;
4127 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4131 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4133 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
4134 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4136 DWORD DestFVF
= dest
->fvf
;
4138 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4142 if (lpStrideData
->u
.s
.normal
.lpData
) {
4143 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4146 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
4147 ERR("Source has no position mask\n");
4148 return WINED3DERR_INVALIDCALL
;
4151 /* We might access VBOs from this code, so hold the lock */
4154 if (dest
->resource
.allocatedMemory
== NULL
) {
4155 /* This may happen if we do direct locking into a vbo. Unlikely,
4156 * but theoretically possible(ddraw processvertices test)
4158 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4159 if(!dest
->resource
.allocatedMemory
) {
4161 ERR("Out of memory\n");
4162 return E_OUTOFMEMORY
;
4166 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4167 checkGLcall("glBindBufferARB");
4168 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4170 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4172 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4173 checkGLcall("glUnmapBufferARB");
4177 /* Get a pointer into the destination vbo(create one if none exists) and
4178 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4180 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
4181 dest
->Flags
|= VBFLAG_CREATEVBO
;
4182 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer
*) dest
);
4186 unsigned char extrabytes
= 0;
4187 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4188 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4189 * this may write 4 extra bytes beyond the area that should be written
4191 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4192 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4193 if(!dest_conv_addr
) {
4194 ERR("Out of memory\n");
4195 /* Continue without storing converted vertices */
4197 dest_conv
= dest_conv_addr
;
4201 * a) WINED3DRS_CLIPPING is enabled
4202 * b) WINED3DVOP_CLIP is passed
4204 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4205 static BOOL warned
= FALSE
;
4207 * The clipping code is not quite correct. Some things need
4208 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4209 * so disable clipping for now.
4210 * (The graphics in Half-Life are broken, and my processvertices
4211 * test crashes with IDirect3DDevice3)
4217 FIXME("Clipping is broken and disabled for now\n");
4219 } else doClip
= FALSE
;
4220 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4222 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4225 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4226 WINED3DTS_PROJECTION
,
4228 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4229 WINED3DTS_WORLDMATRIX(0),
4232 TRACE("View mat:\n");
4233 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
);
4234 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
);
4235 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
);
4236 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
);
4238 TRACE("Proj mat:\n");
4239 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
);
4240 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
);
4241 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
);
4242 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
);
4244 TRACE("World mat:\n");
4245 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
);
4246 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
);
4247 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
);
4248 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
);
4250 /* Get the viewport */
4251 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4252 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4253 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4255 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4256 multiply_matrix(&mat
,&proj_mat
,&mat
);
4258 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4260 for (i
= 0; i
< dwCount
; i
+= 1) {
4261 unsigned int tex_index
;
4263 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4264 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4265 /* The position first */
4267 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4269 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4271 /* Multiplication with world, view and projection matrix */
4272 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
);
4273 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
);
4274 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
);
4275 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
);
4277 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4279 /* WARNING: The following things are taken from d3d7 and were not yet checked
4280 * against d3d8 or d3d9!
4283 /* Clipping conditions: From msdn
4285 * A vertex is clipped if it does not match the following requirements
4289 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4291 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4292 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4297 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4298 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4301 /* "Normal" viewport transformation (not clipped)
4302 * 1) The values are divided by rhw
4303 * 2) The y axis is negative, so multiply it with -1
4304 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4305 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4306 * 4) Multiply x with Width/2 and add Width/2
4307 * 5) The same for the height
4308 * 6) Add the viewpoint X and Y to the 2D coordinates and
4309 * The minimum Z value to z
4310 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4312 * Well, basically it's simply a linear transformation into viewport
4324 z
*= vp
.MaxZ
- vp
.MinZ
;
4326 x
+= vp
.Width
/ 2 + vp
.X
;
4327 y
+= vp
.Height
/ 2 + vp
.Y
;
4332 /* That vertex got clipped
4333 * Contrary to OpenGL it is not dropped completely, it just
4334 * undergoes a different calculation.
4336 TRACE("Vertex got clipped\n");
4343 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4344 * outside of the main vertex buffer memory. That needs some more
4349 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4352 ( (float *) dest_ptr
)[0] = x
;
4353 ( (float *) dest_ptr
)[1] = y
;
4354 ( (float *) dest_ptr
)[2] = z
;
4355 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4357 dest_ptr
+= 3 * sizeof(float);
4359 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4360 dest_ptr
+= sizeof(float);
4365 ( (float *) dest_conv
)[0] = x
* w
;
4366 ( (float *) dest_conv
)[1] = y
* w
;
4367 ( (float *) dest_conv
)[2] = z
* w
;
4368 ( (float *) dest_conv
)[3] = w
;
4370 dest_conv
+= 3 * sizeof(float);
4372 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4373 dest_conv
+= sizeof(float);
4377 if (DestFVF
& WINED3DFVF_PSIZE
) {
4378 dest_ptr
+= sizeof(DWORD
);
4379 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4381 if (DestFVF
& WINED3DFVF_NORMAL
) {
4383 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4384 /* AFAIK this should go into the lighting information */
4385 FIXME("Didn't expect the destination to have a normal\n");
4386 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4388 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4392 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4394 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4396 static BOOL warned
= FALSE
;
4399 ERR("No diffuse color in source, but destination has one\n");
4403 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4404 dest_ptr
+= sizeof(DWORD
);
4407 *( (DWORD
*) dest_conv
) = 0xffffffff;
4408 dest_conv
+= sizeof(DWORD
);
4412 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4414 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4415 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4416 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4417 dest_conv
+= sizeof(DWORD
);
4422 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4423 /* What's the color value in the feedback buffer? */
4425 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4427 static BOOL warned
= FALSE
;
4430 ERR("No specular color in source, but destination has one\n");
4434 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4435 dest_ptr
+= sizeof(DWORD
);
4438 *( (DWORD
*) dest_conv
) = 0xFF000000;
4439 dest_conv
+= sizeof(DWORD
);
4443 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4445 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4446 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4447 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4448 dest_conv
+= sizeof(DWORD
);
4453 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4455 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4456 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4458 ERR("No source texture, but destination requests one\n");
4459 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4460 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4463 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4465 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4472 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4473 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4474 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4475 dwCount
* get_flexible_vertex_size(DestFVF
),
4477 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4478 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4485 #undef copy_and_next
4487 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4489 WineDirect3DVertexStridedData strided
;
4490 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4491 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4494 ERR("Output vertex declaration not implemented yet\n");
4497 /* Need any context to write to the vbo. */
4498 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4500 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4501 * control the streamIsUP flag, thus restore it afterwards.
4503 This
->stateBlock
->streamIsUP
= FALSE
;
4504 memset(&strided
, 0, sizeof(strided
));
4505 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4506 This
->stateBlock
->streamIsUP
= streamWasUP
;
4508 if(vbo
|| SrcStartIndex
) {
4510 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4511 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4513 * Also get the start index in, but only loop over all elements if there's something to add at all.
4515 #define FIXSRC(type) \
4516 if(strided.u.s.type.VBO) { \
4517 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4518 strided.u.s.type.VBO = 0; \
4519 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4521 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4525 if(strided.u.s.type.lpData) { \
4526 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4529 FIXSRC(blendWeights
);
4530 FIXSRC(blendMatrixIndices
);
4535 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4536 FIXSRC(texCoords
[i
]);
4549 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4553 * Get / Set Texture Stage States
4554 * TODO: Verify against dx9 definitions
4556 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4557 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4558 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4560 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4562 if (Stage
>= MAX_TEXTURES
) {
4563 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4567 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4568 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4570 if (This
->isRecordingState
) {
4571 TRACE("Recording... not performing anything\n");
4575 /* Checked after the assignments to allow proper stateblock recording */
4576 if(oldValue
== Value
) {
4577 TRACE("App is setting the old value over, nothing to do\n");
4581 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4582 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4583 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4584 * Changes in other states are important on disabled stages too
4589 if(Type
== WINED3DTSS_COLOROP
) {
4592 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4593 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4594 * they have to be disabled
4596 * The current stage is dirtified below.
4598 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4599 TRACE("Additionally dirtifying stage %d\n", i
);
4600 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4602 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4603 TRACE("New lowest disabled: %d\n", Stage
);
4604 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4605 /* Previously disabled stage enabled. Stages above it may need enabling
4606 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4607 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4609 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4612 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4613 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4616 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4617 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4619 This
->stateBlock
->lowest_disabled_stage
= i
;
4620 TRACE("New lowest disabled: %d\n", i
);
4624 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4629 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4630 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4631 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4632 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4639 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4640 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4641 IWineD3DBaseTexture
*oldTexture
;
4643 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4645 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4646 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4649 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4650 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4651 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4654 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4656 if(pTexture
!= NULL
) {
4657 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4659 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4660 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4661 return WINED3DERR_INVALIDCALL
;
4663 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4666 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4667 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4669 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4670 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4671 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4673 /* Handle recording of state blocks */
4674 if (This
->isRecordingState
) {
4675 TRACE("Recording... not performing anything\n");
4679 if(oldTexture
== pTexture
) {
4680 TRACE("App is setting the same texture again, nothing to do\n");
4684 /** NOTE: MSDN says that setTexture increases the reference count,
4685 * and that the application must set the texture back to null (or have a leaky application),
4686 * This means we should pass the refcount up to the parent
4687 *******************************/
4688 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4689 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4690 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4692 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4693 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4694 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4695 * so the COLOROP and ALPHAOP have to be dirtified.
4697 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4698 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4700 if(bindCount
== 1) {
4701 new->baseTexture
.sampler
= Stage
;
4703 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4707 if (NULL
!= oldTexture
) {
4708 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4709 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4711 IWineD3DBaseTexture_Release(oldTexture
);
4712 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4713 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4714 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4717 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4719 /* Have to do a search for the other sampler(s) where the texture is bound to
4720 * Shouldn't happen as long as apps bind a texture only to one stage
4722 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4723 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4724 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4725 old
->baseTexture
.sampler
= i
;
4732 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4737 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4738 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4740 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4742 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4743 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4746 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4747 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4748 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4751 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4753 IWineD3DBaseTexture_AddRef(*ppTexture
);
4755 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4763 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4764 IWineD3DSurface
**ppBackBuffer
) {
4765 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4766 IWineD3DSwapChain
*swapChain
;
4769 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4771 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4772 if (hr
== WINED3D_OK
) {
4773 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4774 IWineD3DSwapChain_Release(swapChain
);
4776 *ppBackBuffer
= NULL
;
4781 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4782 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4783 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4784 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4787 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4788 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4789 IWineD3DSwapChain
*swapChain
;
4792 if(iSwapChain
> 0) {
4793 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4794 if (hr
== WINED3D_OK
) {
4795 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4796 IWineD3DSwapChain_Release(swapChain
);
4798 FIXME("(%p) Error getting display mode\n", This
);
4801 /* Don't read the real display mode,
4802 but return the stored mode instead. X11 can't change the color
4803 depth, and some apps are pretty angry if they SetDisplayMode from
4804 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4806 Also don't relay to the swapchain because with ddraw it's possible
4807 that there isn't a swapchain at all */
4808 pMode
->Width
= This
->ddraw_width
;
4809 pMode
->Height
= This
->ddraw_height
;
4810 pMode
->Format
= This
->ddraw_format
;
4811 pMode
->RefreshRate
= 0;
4819 * Stateblock related functions
4822 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4823 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4824 IWineD3DStateBlockImpl
*object
;
4825 HRESULT temp_result
;
4828 TRACE("(%p)\n", This
);
4830 if (This
->isRecordingState
) {
4831 return WINED3DERR_INVALIDCALL
;
4834 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4835 if (NULL
== object
) {
4836 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4837 return E_OUTOFMEMORY
;
4839 TRACE("(%p) created object %p\n", This
, object
);
4840 object
->wineD3DDevice
= This
;
4841 /** FIXME: object->parent = parent; **/
4842 object
->parent
= NULL
;
4843 object
->blockType
= WINED3DSBT_RECORDED
;
4845 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4847 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4848 list_init(&object
->lightMap
[i
]);
4851 temp_result
= allocate_shader_constants(object
);
4852 if (WINED3D_OK
!= temp_result
)
4855 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4856 This
->updateStateBlock
= object
;
4857 This
->isRecordingState
= TRUE
;
4859 TRACE("(%p) recording stateblock %p\n",This
, object
);
4863 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4864 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4866 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4868 if (!This
->isRecordingState
) {
4869 FIXME("(%p) not recording! returning error\n", This
);
4870 *ppStateBlock
= NULL
;
4871 return WINED3DERR_INVALIDCALL
;
4874 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4875 if(object
->changed
.renderState
[i
]) {
4876 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4877 object
->num_contained_render_states
++;
4880 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4881 if(object
->changed
.transform
[i
]) {
4882 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4883 object
->num_contained_transform_states
++;
4886 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4887 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4888 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4889 object
->num_contained_vs_consts_f
++;
4892 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4893 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4894 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4895 object
->num_contained_vs_consts_i
++;
4898 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4899 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4900 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4901 object
->num_contained_vs_consts_b
++;
4904 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4905 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4906 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4907 object
->num_contained_ps_consts_i
++;
4910 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4911 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4912 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4913 object
->num_contained_ps_consts_b
++;
4916 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4917 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4918 if(object
->changed
.textureState
[i
][j
]) {
4919 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4920 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4921 object
->num_contained_tss_states
++;
4925 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4926 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4927 if(object
->changed
.samplerState
[i
][j
]) {
4928 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4929 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4930 object
->num_contained_sampler_states
++;
4935 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4936 This
->isRecordingState
= FALSE
;
4937 This
->updateStateBlock
= This
->stateBlock
;
4938 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4939 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4940 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4945 * Scene related functions
4947 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4948 /* At the moment we have no need for any functionality at the beginning
4950 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4951 TRACE("(%p)\n", This
);
4954 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4955 return WINED3DERR_INVALIDCALL
;
4957 This
->inScene
= TRUE
;
4961 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4962 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4963 TRACE("(%p)\n", This
);
4965 if(!This
->inScene
) {
4966 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4967 return WINED3DERR_INVALIDCALL
;
4970 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4971 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4973 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4977 This
->inScene
= FALSE
;
4981 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4982 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4983 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4984 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4985 IWineD3DSwapChain
*swapChain
= NULL
;
4987 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4989 TRACE("(%p) Presenting the frame\n", This
);
4991 for(i
= 0 ; i
< swapchains
; i
++) {
4993 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4994 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4995 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4996 IWineD3DSwapChain_Release(swapChain
);
5002 /* Not called from the VTable (internal subroutine) */
5003 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
5004 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
5005 float Z
, DWORD Stencil
) {
5006 GLbitfield glMask
= 0;
5008 WINED3DRECT curRect
;
5010 WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
5011 UINT drawable_width
, drawable_height
;
5012 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
5013 IWineD3DSwapChainImpl
*swapchain
= NULL
;
5015 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5016 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5017 * for the cleared parts, and the untouched parts.
5019 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5020 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5021 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5022 * checking all this if the dest surface is in the drawable anyway.
5024 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
5026 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
5027 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
5028 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5031 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5032 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5033 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
5034 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
5035 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5038 if(Count
> 0 && pRects
&& (
5039 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5040 pRects
[0].x2
< target
->currentDesc
.Width
||
5041 pRects
[0].y2
< target
->currentDesc
.Height
)) {
5042 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5049 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
5051 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
5054 /* Only set the values up once, as they are not changing */
5055 if (Flags
& WINED3DCLEAR_STENCIL
) {
5056 glClearStencil(Stencil
);
5057 checkGLcall("glClearStencil");
5058 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
5059 glStencilMask(0xFFFFFFFF);
5062 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5063 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5064 glDepthMask(GL_TRUE
);
5066 checkGLcall("glClearDepth");
5067 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
5068 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
5070 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
5071 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
5072 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5074 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5075 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5076 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
5077 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
5078 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5080 else if (Count
> 0 && pRects
&& (
5081 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5082 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
5083 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
5084 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5088 if (Flags
& WINED3DCLEAR_TARGET
) {
5089 TRACE("Clearing screen with glClear to color %x\n", Color
);
5090 glClearColor(D3DCOLOR_R(Color
),
5094 checkGLcall("glClearColor");
5096 /* Clear ALL colors! */
5097 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5098 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
5101 vp_rect
.left
= vp
->X
;
5102 vp_rect
.top
= vp
->Y
;
5103 vp_rect
.right
= vp
->X
+ vp
->Width
;
5104 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5105 if (!(Count
> 0 && pRects
)) {
5106 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5107 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5109 if(This
->render_offscreen
) {
5110 glScissor(vp_rect
.left
, vp_rect
.top
,
5111 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5113 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5114 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5116 checkGLcall("glScissor");
5118 checkGLcall("glClear");
5120 /* Now process each rect in turn */
5121 for (i
= 0; i
< Count
; i
++) {
5122 /* Note gl uses lower left, width/height */
5123 IntersectRect((RECT
*) &curRect
, &vp_rect
, (RECT
*) &pRects
[i
]);
5124 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5125 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5127 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5128 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5129 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5130 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5132 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5133 * The rectangle is not cleared, no error is returned, but further rectanlges are
5134 * still cleared if they are valid
5136 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5137 TRACE("Rectangle with negative dimensions, ignoring\n");
5141 if(This
->render_offscreen
) {
5142 glScissor(curRect
.x1
, curRect
.y1
,
5143 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5145 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5146 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5148 checkGLcall("glScissor");
5151 checkGLcall("glClear");
5155 /* Restore the old values (why..?) */
5156 if (Flags
& WINED3DCLEAR_STENCIL
) {
5157 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5159 if (Flags
& WINED3DCLEAR_TARGET
) {
5160 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5161 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5162 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5163 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5164 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5166 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5167 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5169 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5171 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5172 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5173 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5174 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5179 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5181 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
5184 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5190 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5191 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5192 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5193 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5195 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5196 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5198 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5199 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5200 /* TODO: What about depth stencil buffers without stencil bits? */
5201 return WINED3DERR_INVALIDCALL
;
5204 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5210 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
5211 UINT PrimitiveCount
) {
5213 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5215 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
5216 debug_d3dprimitivetype(PrimitiveType
),
5217 StartVertex
, PrimitiveCount
);
5219 if(!This
->stateBlock
->vertexDecl
) {
5220 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5221 return WINED3DERR_INVALIDCALL
;
5224 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5225 if(This
->stateBlock
->streamIsUP
) {
5226 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5227 This
->stateBlock
->streamIsUP
= FALSE
;
5230 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5231 This
->stateBlock
->loadBaseVertexIndex
= 0;
5232 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5234 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5235 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
5236 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5240 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5241 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5242 WINED3DPRIMITIVETYPE PrimitiveType
,
5243 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
5245 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5247 IWineD3DIndexBuffer
*pIB
;
5248 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
5251 pIB
= This
->stateBlock
->pIndexData
;
5253 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5254 * without an index buffer set. (The first time at least...)
5255 * D3D8 simply dies, but I doubt it can do much harm to return
5256 * D3DERR_INVALIDCALL there as well. */
5257 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5258 return WINED3DERR_INVALIDCALL
;
5261 if(!This
->stateBlock
->vertexDecl
) {
5262 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5263 return WINED3DERR_INVALIDCALL
;
5266 if(This
->stateBlock
->streamIsUP
) {
5267 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5268 This
->stateBlock
->streamIsUP
= FALSE
;
5270 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5272 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5273 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5274 minIndex
, NumVertices
, startIndex
, primCount
);
5276 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5277 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5283 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5284 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5285 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5288 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5289 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5294 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5295 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5296 UINT VertexStreamZeroStride
) {
5297 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5298 IWineD3DVertexBuffer
*vb
;
5300 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5301 debug_d3dprimitivetype(PrimitiveType
),
5302 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5304 if(!This
->stateBlock
->vertexDecl
) {
5305 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5306 return WINED3DERR_INVALIDCALL
;
5309 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5310 vb
= This
->stateBlock
->streamSource
[0];
5311 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5312 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5313 This
->stateBlock
->streamOffset
[0] = 0;
5314 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5315 This
->stateBlock
->streamIsUP
= TRUE
;
5316 This
->stateBlock
->loadBaseVertexIndex
= 0;
5318 /* TODO: Only mark dirty if drawing from a different UP address */
5319 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5321 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5322 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5324 /* MSDN specifies stream zero settings must be set to NULL */
5325 This
->stateBlock
->streamStride
[0] = 0;
5326 This
->stateBlock
->streamSource
[0] = NULL
;
5328 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5329 * the new stream sources or use UP drawing again
5334 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5335 UINT MinVertexIndex
, UINT NumVertices
,
5336 UINT PrimitiveCount
, CONST
void* pIndexData
,
5337 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5338 UINT VertexStreamZeroStride
) {
5340 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5341 IWineD3DVertexBuffer
*vb
;
5342 IWineD3DIndexBuffer
*ib
;
5344 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5345 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5346 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5347 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5349 if(!This
->stateBlock
->vertexDecl
) {
5350 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5351 return WINED3DERR_INVALIDCALL
;
5354 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5360 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5361 vb
= This
->stateBlock
->streamSource
[0];
5362 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5363 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5364 This
->stateBlock
->streamIsUP
= TRUE
;
5365 This
->stateBlock
->streamOffset
[0] = 0;
5366 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5368 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5369 This
->stateBlock
->baseVertexIndex
= 0;
5370 This
->stateBlock
->loadBaseVertexIndex
= 0;
5371 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5372 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5373 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5375 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5377 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5378 This
->stateBlock
->streamSource
[0] = NULL
;
5379 This
->stateBlock
->streamStride
[0] = 0;
5380 ib
= This
->stateBlock
->pIndexData
;
5382 IWineD3DIndexBuffer_Release(ib
);
5383 This
->stateBlock
->pIndexData
= NULL
;
5385 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5386 * SetStreamSource to specify a vertex buffer
5392 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5395 /* Mark the state dirty until we have nicer tracking
5396 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5399 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5400 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5401 This
->stateBlock
->baseVertexIndex
= 0;
5402 This
->up_strided
= DrawPrimStrideData
;
5403 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5404 This
->up_strided
= NULL
;
5408 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5409 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5410 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5412 /* Mark the state dirty until we have nicer tracking
5413 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5416 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5417 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5418 This
->stateBlock
->streamIsUP
= TRUE
;
5419 This
->stateBlock
->baseVertexIndex
= 0;
5420 This
->up_strided
= DrawPrimStrideData
;
5421 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5422 This
->up_strided
= NULL
;
5426 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5427 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5428 * not callable by the app directly no parameter validation checks are needed here.
5430 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5431 WINED3DLOCKED_BOX src
;
5432 WINED3DLOCKED_BOX dst
;
5434 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5436 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5437 * dirtification to improve loading performance.
5439 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5440 if(FAILED(hr
)) return hr
;
5441 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5443 IWineD3DVolume_UnlockBox(pSourceVolume
);
5447 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5449 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5451 IWineD3DVolume_UnlockBox(pSourceVolume
);
5453 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5458 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5459 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5460 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5461 HRESULT hr
= WINED3D_OK
;
5462 WINED3DRESOURCETYPE sourceType
;
5463 WINED3DRESOURCETYPE destinationType
;
5466 /* TODO: think about moving the code into IWineD3DBaseTexture */
5468 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5470 /* verify that the source and destination textures aren't NULL */
5471 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5472 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5473 This
, pSourceTexture
, pDestinationTexture
);
5474 hr
= WINED3DERR_INVALIDCALL
;
5477 if (pSourceTexture
== pDestinationTexture
) {
5478 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5479 This
, pSourceTexture
, pDestinationTexture
);
5480 hr
= WINED3DERR_INVALIDCALL
;
5482 /* Verify that the source and destination textures are the same type */
5483 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5484 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5486 if (sourceType
!= destinationType
) {
5487 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5489 hr
= WINED3DERR_INVALIDCALL
;
5492 /* check that both textures have the identical numbers of levels */
5493 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5494 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5495 hr
= WINED3DERR_INVALIDCALL
;
5498 if (WINED3D_OK
== hr
) {
5500 /* Make sure that the destination texture is loaded */
5501 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5503 /* Update every surface level of the texture */
5504 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5506 switch (sourceType
) {
5507 case WINED3DRTYPE_TEXTURE
:
5509 IWineD3DSurface
*srcSurface
;
5510 IWineD3DSurface
*destSurface
;
5512 for (i
= 0 ; i
< levels
; ++i
) {
5513 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5514 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5515 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5516 IWineD3DSurface_Release(srcSurface
);
5517 IWineD3DSurface_Release(destSurface
);
5518 if (WINED3D_OK
!= hr
) {
5519 WARN("(%p) : Call to update surface failed\n", This
);
5525 case WINED3DRTYPE_CUBETEXTURE
:
5527 IWineD3DSurface
*srcSurface
;
5528 IWineD3DSurface
*destSurface
;
5529 WINED3DCUBEMAP_FACES faceType
;
5531 for (i
= 0 ; i
< levels
; ++i
) {
5532 /* Update each cube face */
5533 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5534 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5535 if (WINED3D_OK
!= hr
) {
5536 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5538 TRACE("Got srcSurface %p\n", srcSurface
);
5540 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5541 if (WINED3D_OK
!= hr
) {
5542 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5544 TRACE("Got desrSurface %p\n", destSurface
);
5546 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5547 IWineD3DSurface_Release(srcSurface
);
5548 IWineD3DSurface_Release(destSurface
);
5549 if (WINED3D_OK
!= hr
) {
5550 WARN("(%p) : Call to update surface failed\n", This
);
5558 case WINED3DRTYPE_VOLUMETEXTURE
:
5560 IWineD3DVolume
*srcVolume
= NULL
;
5561 IWineD3DVolume
*destVolume
= NULL
;
5563 for (i
= 0 ; i
< levels
; ++i
) {
5564 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5565 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5566 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5567 IWineD3DVolume_Release(srcVolume
);
5568 IWineD3DVolume_Release(destVolume
);
5569 if (WINED3D_OK
!= hr
) {
5570 WARN("(%p) : Call to update volume failed\n", This
);
5578 FIXME("(%p) : Unsupported source and destination type\n", This
);
5579 hr
= WINED3DERR_INVALIDCALL
;
5586 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5587 IWineD3DSwapChain
*swapChain
;
5589 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5590 if(hr
== WINED3D_OK
) {
5591 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5592 IWineD3DSwapChain_Release(swapChain
);
5597 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5598 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5599 IWineD3DBaseTextureImpl
*texture
;
5600 const GlPixelFormatDesc
*gl_info
;
5603 TRACE("(%p) : %p\n", This
, pNumPasses
);
5605 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5606 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
5607 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5608 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5610 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
5611 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5612 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5615 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
5616 if(!texture
) continue;
5617 getFormatDescEntry(texture
->resource
.format
, &GLINFO_LOCATION
, &gl_info
);
5618 if(gl_info
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
5620 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
5621 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
5624 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
5625 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
5628 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
5629 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
5630 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
5635 /* return a sensible default */
5638 TRACE("returning D3D_OK\n");
5642 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5646 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5647 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5648 if (texture
&& (texture
->resource
.format
== WINED3DFMT_P8
|| texture
->resource
.format
== WINED3DFMT_A8P8
)) {
5649 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5654 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5655 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5658 PALETTEENTRY
**palettes
;
5660 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5662 if (PaletteNumber
>= MAX_PALETTES
) {
5663 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5664 return WINED3DERR_INVALIDCALL
;
5667 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5668 NewSize
= This
->NumberOfPalettes
;
5671 } while(PaletteNumber
>= NewSize
);
5672 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5674 ERR("Out of memory!\n");
5675 return E_OUTOFMEMORY
;
5677 This
->palettes
= palettes
;
5678 This
->NumberOfPalettes
= NewSize
;
5681 if (!This
->palettes
[PaletteNumber
]) {
5682 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5683 if (!This
->palettes
[PaletteNumber
]) {
5684 ERR("Out of memory!\n");
5685 return E_OUTOFMEMORY
;
5689 for (j
= 0; j
< 256; ++j
) {
5690 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5691 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5692 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5693 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5695 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5696 TRACE("(%p) : returning\n", This
);
5700 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5701 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5703 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5704 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5705 /* What happens in such situation isn't documented; Native seems to silently abort
5706 on such conditions. Return Invalid Call. */
5707 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5708 return WINED3DERR_INVALIDCALL
;
5710 for (j
= 0; j
< 256; ++j
) {
5711 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5712 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5713 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5714 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5716 TRACE("(%p) : returning\n", This
);
5720 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5721 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5722 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5723 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5724 (tested with reference rasterizer). Return Invalid Call. */
5725 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5726 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5727 return WINED3DERR_INVALIDCALL
;
5729 /*TODO: stateblocks */
5730 if (This
->currentPalette
!= PaletteNumber
) {
5731 This
->currentPalette
= PaletteNumber
;
5732 dirtify_p8_texture_samplers(This
);
5734 TRACE("(%p) : returning\n", This
);
5738 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5739 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5740 if (PaletteNumber
== NULL
) {
5741 WARN("(%p) : returning Invalid Call\n", This
);
5742 return WINED3DERR_INVALIDCALL
;
5744 /*TODO: stateblocks */
5745 *PaletteNumber
= This
->currentPalette
;
5746 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5750 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5751 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5752 static BOOL showFixmes
= TRUE
;
5754 FIXME("(%p) : stub\n", This
);
5758 This
->softwareVertexProcessing
= bSoftware
;
5763 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5764 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5765 static BOOL showFixmes
= TRUE
;
5767 FIXME("(%p) : stub\n", This
);
5770 return This
->softwareVertexProcessing
;
5774 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5775 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5776 IWineD3DSwapChain
*swapChain
;
5779 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5781 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5782 if(hr
== WINED3D_OK
){
5783 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5784 IWineD3DSwapChain_Release(swapChain
);
5786 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5792 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5793 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5794 static BOOL showfixmes
= TRUE
;
5795 if(nSegments
!= 0.0f
) {
5797 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5804 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5805 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5806 static BOOL showfixmes
= TRUE
;
5808 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5814 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5815 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5816 /** TODO: remove casts to IWineD3DSurfaceImpl
5817 * NOTE: move code to surface to accomplish this
5818 ****************************************/
5819 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5820 int srcWidth
, srcHeight
;
5821 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5822 WINED3DFORMAT destFormat
, srcFormat
;
5824 int srcLeft
, destLeft
, destTop
;
5825 WINED3DPOOL srcPool
, destPool
;
5827 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5828 glDescriptor
*glDescription
= NULL
;
5832 CONVERT_TYPES convert
= NO_CONVERSION
;
5834 WINED3DSURFACE_DESC winedesc
;
5836 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5837 memset(&winedesc
, 0, sizeof(winedesc
));
5838 winedesc
.Width
= &srcSurfaceWidth
;
5839 winedesc
.Height
= &srcSurfaceHeight
;
5840 winedesc
.Pool
= &srcPool
;
5841 winedesc
.Format
= &srcFormat
;
5843 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5845 winedesc
.Width
= &destSurfaceWidth
;
5846 winedesc
.Height
= &destSurfaceHeight
;
5847 winedesc
.Pool
= &destPool
;
5848 winedesc
.Format
= &destFormat
;
5849 winedesc
.Size
= &destSize
;
5851 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5853 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5854 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5855 return WINED3DERR_INVALIDCALL
;
5858 /* This call loads the opengl surface directly, instead of copying the surface to the
5859 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5860 * copy in sysmem and use regular surface loading.
5862 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5863 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5864 if(convert
!= NO_CONVERSION
) {
5865 return IWineD3DSurface_BltFast(pDestinationSurface
,
5866 pDestPoint
? pDestPoint
->x
: 0,
5867 pDestPoint
? pDestPoint
->y
: 0,
5868 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5871 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5872 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5873 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5875 /* Get the update surface description */
5876 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5879 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5883 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5884 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5885 checkGLcall("glActiveTextureARB");
5888 /* Make sure the surface is loaded and up to date */
5889 IWineD3DSurface_PreLoad(pDestinationSurface
);
5890 IWineD3DSurface_BindTexture(pDestinationSurface
);
5892 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5894 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5895 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5896 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5897 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5898 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5899 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5902 /* This function doesn't support compressed textures
5903 the pitch is just bytesPerPixel * width */
5904 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5905 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5906 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5907 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5909 /* TODO DXT formats */
5911 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5912 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5914 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5915 This
, glDescription
->level
, destLeft
, destTop
, srcWidth
, srcHeight
, glDescription
->glFormat
,
5916 glDescription
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5919 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5921 /* need to lock the surface to get the data */
5922 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5925 /* TODO: Cube and volume support */
5927 /* not a whole row so we have to do it a line at a time */
5930 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5931 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5933 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5935 glTexSubImage2D(glDescription
->target
5936 ,glDescription
->level
5941 ,glDescription
->glFormat
5942 ,glDescription
->glType
5943 ,data
/* could be quicker using */
5948 } else { /* Full width, so just write out the whole texture */
5949 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5951 if (WINED3DFMT_DXT1
== destFormat
||
5952 WINED3DFMT_DXT2
== destFormat
||
5953 WINED3DFMT_DXT3
== destFormat
||
5954 WINED3DFMT_DXT4
== destFormat
||
5955 WINED3DFMT_DXT5
== destFormat
) {
5956 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5957 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5958 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5959 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5960 } if (destFormat
!= srcFormat
) {
5961 FIXME("Updating mixed format compressed texture is not curretly support\n");
5963 GL_EXTCALL(glCompressedTexImage2DARB(glDescription
->target
, glDescription
->level
,
5964 glDescription
->glFormatInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5967 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5972 glTexSubImage2D(glDescription
->target
, glDescription
->level
, destLeft
, destTop
,
5973 srcWidth
, srcHeight
, glDescription
->glFormat
, glDescription
->glType
, data
);
5976 checkGLcall("glTexSubImage2D");
5980 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5981 sampler
= This
->rev_tex_unit_map
[0];
5982 if (sampler
!= -1) {
5983 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5989 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5990 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5991 struct WineD3DRectPatch
*patch
;
5995 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5997 if(!(Handle
|| pRectPatchInfo
)) {
5998 /* TODO: Write a test for the return value, thus the FIXME */
5999 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6000 return WINED3DERR_INVALIDCALL
;
6004 i
= PATCHMAP_HASHFUNC(Handle
);
6006 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6007 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6008 if(patch
->Handle
== Handle
) {
6015 TRACE("Patch does not exist. Creating a new one\n");
6016 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6017 patch
->Handle
= Handle
;
6018 list_add_head(&This
->patches
[i
], &patch
->entry
);
6020 TRACE("Found existing patch %p\n", patch
);
6023 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6024 * attributes we have to tesselate, read back, and draw. This needs a patch
6025 * management structure instance. Create one.
6027 * A possible improvement is to check if a vertex shader is used, and if not directly
6030 FIXME("Drawing an uncached patch. This is slow\n");
6031 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6034 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
6035 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
6036 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
6038 TRACE("Tesselation density or patch info changed, retesselating\n");
6040 if(pRectPatchInfo
) {
6041 patch
->RectPatchInfo
= *pRectPatchInfo
;
6043 patch
->numSegs
[0] = pNumSegs
[0];
6044 patch
->numSegs
[1] = pNumSegs
[1];
6045 patch
->numSegs
[2] = pNumSegs
[2];
6046 patch
->numSegs
[3] = pNumSegs
[3];
6048 hr
= tesselate_rectpatch(This
, patch
);
6050 WARN("Patch tesselation failed\n");
6052 /* Do not release the handle to store the params of the patch */
6054 HeapFree(GetProcessHeap(), 0, patch
);
6060 This
->currentPatch
= patch
;
6061 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
6062 This
->currentPatch
= NULL
;
6064 /* Destroy uncached patches */
6066 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6067 HeapFree(GetProcessHeap(), 0, patch
);
6072 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
6073 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6074 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
6075 FIXME("(%p) : Stub\n", This
);
6079 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
6080 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6082 struct WineD3DRectPatch
*patch
;
6084 TRACE("(%p) Handle(%d)\n", This
, Handle
);
6086 i
= PATCHMAP_HASHFUNC(Handle
);
6087 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6088 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6089 if(patch
->Handle
== Handle
) {
6090 TRACE("Deleting patch %p\n", patch
);
6091 list_remove(&patch
->entry
);
6092 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6093 HeapFree(GetProcessHeap(), 0, patch
);
6098 /* TODO: Write a test for the return value */
6099 FIXME("Attempt to destroy nonexistent patch\n");
6100 return WINED3DERR_INVALIDCALL
;
6103 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6105 IWineD3DSwapChain
*swapchain
;
6107 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6108 if (SUCCEEDED(hr
)) {
6109 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6116 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
6117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6118 IWineD3DSwapChain
*swapchain
;
6120 swapchain
= get_swapchain(surface
);
6124 TRACE("Surface %p is onscreen\n", surface
);
6126 ActivateContext(This
, surface
, CTXUSAGE_RESOURCELOAD
);
6128 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6129 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6130 glDrawBuffer(buffer
);
6131 checkGLcall("glDrawBuffer()");
6133 TRACE("Surface %p is offscreen\n", surface
);
6135 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6137 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6138 context_attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6139 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6140 checkGLcall("glFramebufferRenderbufferEXT");
6144 glEnable(GL_SCISSOR_TEST
);
6146 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6148 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6149 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6151 checkGLcall("glScissor");
6152 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
6154 glDisable(GL_SCISSOR_TEST
);
6156 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6158 glDisable(GL_BLEND
);
6159 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
6161 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6162 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6164 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
6165 glClear(GL_COLOR_BUFFER_BIT
);
6166 checkGLcall("glClear");
6168 if (This
->activeContext
->current_fbo
) {
6169 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6171 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6172 checkGLcall("glBindFramebuffer()");
6175 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6176 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6177 glDrawBuffer(GL_BACK
);
6178 checkGLcall("glDrawBuffer()");
6184 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6185 unsigned int r
, g
, b
, a
;
6188 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6189 destfmt
== WINED3DFMT_R8G8B8
)
6192 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6194 a
= (color
& 0xff000000) >> 24;
6195 r
= (color
& 0x00ff0000) >> 16;
6196 g
= (color
& 0x0000ff00) >> 8;
6197 b
= (color
& 0x000000ff) >> 0;
6201 case WINED3DFMT_R5G6B5
:
6202 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6209 TRACE("Returning %08x\n", ret
);
6212 case WINED3DFMT_X1R5G5B5
:
6213 case WINED3DFMT_A1R5G5B5
:
6222 TRACE("Returning %08x\n", ret
);
6226 TRACE("Returning %08x\n", a
);
6229 case WINED3DFMT_X4R4G4B4
:
6230 case WINED3DFMT_A4R4G4B4
:
6239 TRACE("Returning %08x\n", ret
);
6242 case WINED3DFMT_R3G3B2
:
6249 TRACE("Returning %08x\n", ret
);
6252 case WINED3DFMT_X8B8G8R8
:
6253 case WINED3DFMT_A8B8G8R8
:
6258 TRACE("Returning %08x\n", ret
);
6261 case WINED3DFMT_A2R10G10B10
:
6263 r
= (r
* 1024) / 256;
6264 g
= (g
* 1024) / 256;
6265 b
= (b
* 1024) / 256;
6270 TRACE("Returning %08x\n", ret
);
6273 case WINED3DFMT_A2B10G10R10
:
6275 r
= (r
* 1024) / 256;
6276 g
= (g
* 1024) / 256;
6277 b
= (b
* 1024) / 256;
6282 TRACE("Returning %08x\n", ret
);
6286 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6291 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6292 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6293 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6295 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6297 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6298 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6299 return WINED3DERR_INVALIDCALL
;
6302 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6303 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6306 /* Just forward this to the DirectDraw blitting engine */
6307 memset(&BltFx
, 0, sizeof(BltFx
));
6308 BltFx
.dwSize
= sizeof(BltFx
);
6309 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6310 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6314 /* rendertarget and depth stencil functions */
6315 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6316 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6318 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6319 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6320 return WINED3DERR_INVALIDCALL
;
6323 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6324 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6325 /* Note inc ref on returned surface */
6326 if(*ppRenderTarget
!= NULL
)
6327 IWineD3DSurface_AddRef(*ppRenderTarget
);
6331 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6332 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6333 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6334 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6335 IWineD3DSwapChainImpl
*Swapchain
;
6338 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6340 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6341 if(hr
!= WINED3D_OK
) {
6342 ERR("Can't get the swapchain\n");
6346 /* Make sure to release the swapchain */
6347 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6349 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6350 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6351 return WINED3DERR_INVALIDCALL
;
6353 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6354 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6355 return WINED3DERR_INVALIDCALL
;
6358 if(Swapchain
->frontBuffer
!= Front
) {
6359 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6361 if(Swapchain
->frontBuffer
)
6362 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6363 Swapchain
->frontBuffer
= Front
;
6365 if(Swapchain
->frontBuffer
) {
6366 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6370 if(Back
&& !Swapchain
->backBuffer
) {
6371 /* We need memory for the back buffer array - only one back buffer this way */
6372 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6373 if(!Swapchain
->backBuffer
) {
6374 ERR("Out of memory\n");
6375 return E_OUTOFMEMORY
;
6379 if(Swapchain
->backBuffer
[0] != Back
) {
6380 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6382 /* What to do about the context here in the case of multithreading? Not sure.
6383 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6386 if(!Swapchain
->backBuffer
[0]) {
6387 /* GL was told to draw to the front buffer at creation,
6390 glDrawBuffer(GL_BACK
);
6391 checkGLcall("glDrawBuffer(GL_BACK)");
6392 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6393 Swapchain
->presentParms
.BackBufferCount
= 1;
6395 /* That makes problems - disable for now */
6396 /* glDrawBuffer(GL_FRONT); */
6397 checkGLcall("glDrawBuffer(GL_FRONT)");
6398 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6399 Swapchain
->presentParms
.BackBufferCount
= 0;
6403 if(Swapchain
->backBuffer
[0])
6404 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6405 Swapchain
->backBuffer
[0] = Back
;
6407 if(Swapchain
->backBuffer
[0]) {
6408 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6410 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6411 Swapchain
->backBuffer
= NULL
;
6419 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6420 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6421 *ppZStencilSurface
= This
->stencilBufferTarget
;
6422 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6424 if(*ppZStencilSurface
!= NULL
) {
6425 /* Note inc ref on returned surface */
6426 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6429 return WINED3DERR_NOTFOUND
;
6433 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6434 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6435 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6436 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6437 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6439 POINT offset
= {0, 0};
6441 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6442 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6443 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6444 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6447 case WINED3DTEXF_LINEAR
:
6448 gl_filter
= GL_LINEAR
;
6452 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6453 case WINED3DTEXF_NONE
:
6454 case WINED3DTEXF_POINT
:
6455 gl_filter
= GL_NEAREST
;
6459 /* Attach src surface to src fbo */
6460 src_swapchain
= get_swapchain(src_surface
);
6461 if (src_swapchain
) {
6462 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6464 TRACE("Source surface %p is onscreen\n", src_surface
);
6465 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6466 /* Make sure the drawable is up to date. In the offscreen case
6467 * attach_surface_fbo() implicitly takes care of this. */
6468 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6470 if(buffer
== GL_FRONT
) {
6473 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
6474 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
6475 h
= windowsize
.bottom
- windowsize
.top
;
6476 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6477 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6478 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6480 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6481 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6485 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6486 glReadBuffer(buffer
);
6487 checkGLcall("glReadBuffer()");
6489 TRACE("Source surface %p is offscreen\n", src_surface
);
6491 context_bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->activeContext
->src_fbo
);
6492 context_attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6493 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6494 checkGLcall("glReadBuffer()");
6495 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6496 checkGLcall("glFramebufferRenderbufferEXT");
6500 /* Attach dst surface to dst fbo */
6501 dst_swapchain
= get_swapchain(dst_surface
);
6502 if (dst_swapchain
) {
6503 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6505 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6506 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6507 /* Make sure the drawable is up to date. In the offscreen case
6508 * attach_surface_fbo() implicitly takes care of this. */
6509 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6511 if(buffer
== GL_FRONT
) {
6514 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
6515 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
6516 h
= windowsize
.bottom
- windowsize
.top
;
6517 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6518 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6519 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6521 /* Screen coords = window coords, surface height = window height */
6522 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6523 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6527 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6528 glDrawBuffer(buffer
);
6529 checkGLcall("glDrawBuffer()");
6531 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6533 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6534 if(!src_swapchain
) {
6535 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6539 context_bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6540 context_attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6541 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6542 checkGLcall("glDrawBuffer()");
6543 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6544 checkGLcall("glFramebufferRenderbufferEXT");
6546 glDisable(GL_SCISSOR_TEST
);
6547 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6550 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6551 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6552 checkGLcall("glBlitFramebuffer()");
6554 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6555 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6556 checkGLcall("glBlitFramebuffer()");
6559 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6561 if (This
->activeContext
->current_fbo
) {
6562 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6564 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6565 checkGLcall("glBindFramebuffer()");
6568 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6569 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6570 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6571 glDrawBuffer(GL_BACK
);
6572 checkGLcall("glDrawBuffer()");
6577 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6579 WINED3DVIEWPORT viewport
;
6581 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6583 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6584 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6585 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6586 return WINED3DERR_INVALIDCALL
;
6589 /* MSDN says that null disables the render target
6590 but a device must always be associated with a render target
6591 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6593 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6594 FIXME("Trying to set render target 0 to NULL\n");
6595 return WINED3DERR_INVALIDCALL
;
6597 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6598 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
);
6599 return WINED3DERR_INVALIDCALL
;
6602 /* If we are trying to set what we already have, don't bother */
6603 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6604 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6607 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6608 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6609 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6611 /* Render target 0 is special */
6612 if(RenderTargetIndex
== 0) {
6613 /* Finally, reset the viewport as the MSDN states. */
6614 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6615 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6618 viewport
.MaxZ
= 1.0f
;
6619 viewport
.MinZ
= 0.0f
;
6620 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6621 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6622 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6624 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6629 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6630 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6631 HRESULT hr
= WINED3D_OK
;
6632 IWineD3DSurface
*tmp
;
6634 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6636 if (pNewZStencil
== This
->stencilBufferTarget
) {
6637 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6639 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6640 * depending on the renter target implementation being used.
6641 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6642 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6643 * stencil buffer and incur an extra memory overhead
6644 ******************************************************/
6646 if (This
->stencilBufferTarget
) {
6647 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6648 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
6649 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
6651 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6652 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6653 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6657 tmp
= This
->stencilBufferTarget
;
6658 This
->stencilBufferTarget
= pNewZStencil
;
6659 /* should we be calling the parent or the wined3d surface? */
6660 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6661 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6664 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6665 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6666 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6667 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6668 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6675 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6676 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6677 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6678 /* TODO: the use of Impl is deprecated. */
6679 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6680 WINED3DLOCKED_RECT lockedRect
;
6682 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6684 /* some basic validation checks */
6685 if(This
->cursorTexture
) {
6686 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6688 glDeleteTextures(1, &This
->cursorTexture
);
6690 This
->cursorTexture
= 0;
6693 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6694 This
->haveHardwareCursor
= TRUE
;
6696 This
->haveHardwareCursor
= FALSE
;
6699 WINED3DLOCKED_RECT rect
;
6701 /* MSDN: Cursor must be A8R8G8B8 */
6702 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6703 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6704 return WINED3DERR_INVALIDCALL
;
6707 /* MSDN: Cursor must be smaller than the display mode */
6708 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6709 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6710 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
);
6711 return WINED3DERR_INVALIDCALL
;
6714 if (!This
->haveHardwareCursor
) {
6715 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6717 /* Do not store the surface's pointer because the application may
6718 * release it after setting the cursor image. Windows doesn't
6719 * addref the set surface, so we can't do this either without
6720 * creating circular refcount dependencies. Copy out the gl texture
6723 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6724 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6725 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6727 const GlPixelFormatDesc
*glDesc
;
6728 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6729 char *mem
, *bits
= (char *)rect
.pBits
;
6730 GLint intfmt
= glDesc
->glInternal
;
6731 GLint format
= glDesc
->glFormat
;
6732 GLint type
= glDesc
->glType
;
6733 INT height
= This
->cursorHeight
;
6734 INT width
= This
->cursorWidth
;
6735 INT bpp
= tableEntry
->bpp
;
6738 /* Reformat the texture memory (pitch and width can be
6740 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6741 for(i
= 0; i
< height
; i
++)
6742 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6743 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6746 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6747 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6748 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6751 /* Make sure that a proper texture unit is selected */
6752 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6753 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6754 checkGLcall("glActiveTextureARB");
6756 sampler
= This
->rev_tex_unit_map
[0];
6757 if (sampler
!= -1) {
6758 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6760 /* Create a new cursor texture */
6761 glGenTextures(1, &This
->cursorTexture
);
6762 checkGLcall("glGenTextures");
6763 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6764 checkGLcall("glBindTexture");
6765 /* Copy the bitmap memory into the cursor texture */
6766 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6767 HeapFree(GetProcessHeap(), 0, mem
);
6768 checkGLcall("glTexImage2D");
6770 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6771 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6772 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6779 FIXME("A cursor texture was not returned.\n");
6780 This
->cursorTexture
= 0;
6785 /* Draw a hardware cursor */
6786 ICONINFO cursorInfo
;
6788 /* Create and clear maskBits because it is not needed for
6789 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6791 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6792 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6793 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6794 WINED3DLOCK_NO_DIRTY_UPDATE
|
6795 WINED3DLOCK_READONLY
6797 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6798 pSur
->currentDesc
.Height
);
6800 cursorInfo
.fIcon
= FALSE
;
6801 cursorInfo
.xHotspot
= XHotSpot
;
6802 cursorInfo
.yHotspot
= YHotSpot
;
6803 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6804 pSur
->currentDesc
.Height
, 1,
6806 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6807 pSur
->currentDesc
.Height
, 1,
6808 32, lockedRect
.pBits
);
6809 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6810 /* Create our cursor and clean up. */
6811 cursor
= CreateIconIndirect(&cursorInfo
);
6813 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6814 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6815 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6816 This
->hardwareCursor
= cursor
;
6817 HeapFree(GetProcessHeap(), 0, maskBits
);
6821 This
->xHotSpot
= XHotSpot
;
6822 This
->yHotSpot
= YHotSpot
;
6826 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6827 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6828 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6830 This
->xScreenSpace
= XScreenSpace
;
6831 This
->yScreenSpace
= YScreenSpace
;
6837 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6838 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6839 BOOL oldVisible
= This
->bCursorVisible
;
6842 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6845 * When ShowCursor is first called it should make the cursor appear at the OS's last
6846 * known cursor position. Because of this, some applications just repetitively call
6847 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6850 This
->xScreenSpace
= pt
.x
;
6851 This
->yScreenSpace
= pt
.y
;
6853 if (This
->haveHardwareCursor
) {
6854 This
->bCursorVisible
= bShow
;
6856 SetCursor(This
->hardwareCursor
);
6862 if (This
->cursorTexture
)
6863 This
->bCursorVisible
= bShow
;
6869 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6870 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6871 IWineD3DResourceImpl
*resource
;
6872 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6874 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6875 switch (This
->state
) {
6878 case WINED3DERR_DEVICELOST
:
6880 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6881 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
6882 return WINED3DERR_DEVICENOTRESET
;
6884 return WINED3DERR_DEVICELOST
;
6886 case WINED3DERR_DRIVERINTERNALERROR
:
6887 return WINED3DERR_DRIVERINTERNALERROR
;
6891 return WINED3DERR_DRIVERINTERNALERROR
;
6895 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6897 /** FIXME: Resource tracking needs to be done,
6898 * The closes we can do to this is set the priorities of all managed textures low
6899 * and then reset them.
6900 ***********************************************************/
6901 FIXME("(%p) : stub\n", This
);
6905 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6906 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6908 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6909 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6910 /* Release the DC */
6911 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6912 DeleteDC(surface
->hDC
);
6913 /* Release the DIB section */
6914 DeleteObject(surface
->dib
.DIBsection
);
6915 surface
->dib
.bitmap_data
= NULL
;
6916 surface
->resource
.allocatedMemory
= NULL
;
6917 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6919 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6920 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6921 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
6922 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
6923 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6924 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6926 surface
->pow2Width
= surface
->pow2Height
= 1;
6927 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6928 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6930 surface
->glRect
.left
= 0;
6931 surface
->glRect
.top
= 0;
6932 surface
->glRect
.right
= surface
->pow2Width
;
6933 surface
->glRect
.bottom
= surface
->pow2Height
;
6935 if(surface
->glDescription
.textureName
) {
6936 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6938 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6940 surface
->glDescription
.textureName
= 0;
6941 surface
->Flags
&= ~SFLAG_CLIENT
;
6943 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6944 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6945 surface
->Flags
|= SFLAG_NONPOW2
;
6947 surface
->Flags
&= ~SFLAG_NONPOW2
;
6949 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6950 surface
->resource
.allocatedMemory
= NULL
;
6951 surface
->resource
.heapMemory
= NULL
;
6952 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6953 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6954 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
6955 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
6957 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
6961 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6962 TRACE("Unloading resource %p\n", resource
);
6963 IWineD3DResource_UnLoad(resource
);
6964 IWineD3DResource_Release(resource
);
6968 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, WINED3DPRESENT_PARAMETERS
*pp
) {
6970 WINED3DDISPLAYMODE m
;
6973 /* All Windowed modes are supported, as is leaving the current mode */
6974 if(pp
->Windowed
) return TRUE
;
6975 if(!pp
->BackBufferWidth
) return TRUE
;
6976 if(!pp
->BackBufferHeight
) return TRUE
;
6978 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
6979 for(i
= 0; i
< count
; i
++) {
6980 memset(&m
, 0, sizeof(m
));
6981 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
6983 ERR("EnumAdapterModes failed\n");
6985 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6986 /* Mode found, it is supported */
6990 /* Mode not found -> not supported */
6994 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6995 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6996 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6998 IWineD3DBaseShaderImpl
*shader
;
7000 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
7001 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
7002 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
7006 if(This
->depth_blt_texture
) {
7007 glDeleteTextures(1, &This
->depth_blt_texture
);
7008 This
->depth_blt_texture
= 0;
7010 if (This
->depth_blt_rb
) {
7011 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
7012 This
->depth_blt_rb
= 0;
7013 This
->depth_blt_rb_w
= 0;
7014 This
->depth_blt_rb_h
= 0;
7016 This
->blitter
->free_private(iface
);
7017 This
->frag_pipe
->free_private(iface
);
7018 This
->shader_backend
->shader_free_private(iface
);
7020 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
7021 /* Textures are recreated below */
7022 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
7023 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7024 This
->dummyTextureName
[i
] = 0;
7028 while(This
->numContexts
) {
7029 DestroyContext(This
, This
->contexts
[0]);
7031 This
->activeContext
= NULL
;
7032 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
7033 swapchain
->context
= NULL
;
7034 swapchain
->num_contexts
= 0;
7037 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
7038 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7039 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
7041 IWineD3DSurfaceImpl
*target
;
7043 /* Recreate the primary swapchain's context */
7044 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
7045 if(swapchain
->backBuffer
) {
7046 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
7048 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
7050 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
7051 &swapchain
->presentParms
);
7052 swapchain
->num_contexts
= 1;
7053 This
->activeContext
= swapchain
->context
[0];
7055 create_dummy_textures(This
);
7057 hr
= This
->shader_backend
->shader_alloc_private(iface
);
7059 ERR("Failed to recreate shader private data\n");
7062 hr
= This
->frag_pipe
->alloc_private(iface
);
7064 TRACE("Fragment pipeline private data couldn't be allocated\n");
7067 hr
= This
->blitter
->alloc_private(iface
);
7069 TRACE("Blitter private data couldn't be allocated\n");
7076 This
->blitter
->free_private(iface
);
7077 This
->frag_pipe
->free_private(iface
);
7078 This
->shader_backend
->shader_free_private(iface
);
7082 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7083 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7084 IWineD3DSwapChainImpl
*swapchain
;
7086 BOOL DisplayModeChanged
= FALSE
;
7087 WINED3DDISPLAYMODE mode
;
7088 TRACE("(%p)\n", This
);
7090 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7092 ERR("Failed to get the first implicit swapchain\n");
7096 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7097 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7098 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7099 pPresentationParameters
->BackBufferHeight
);
7100 return WINED3DERR_INVALIDCALL
;
7103 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7104 * on an existing gl context, so there's no real need for recreation.
7106 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7108 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7110 TRACE("New params:\n");
7111 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7112 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7113 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7114 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7115 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7116 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7117 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7118 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7119 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7120 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7121 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7122 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7123 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7125 /* No special treatment of these parameters. Just store them */
7126 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7127 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7128 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7129 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7131 /* What to do about these? */
7132 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7133 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7134 ERR("Cannot change the back buffer count yet\n");
7136 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7137 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7138 ERR("Cannot change the back buffer format yet\n");
7140 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7141 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7142 ERR("Cannot change the device window yet\n");
7144 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
7145 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7146 return WINED3DERR_INVALIDCALL
;
7149 /* Reset the depth stencil */
7150 if (pPresentationParameters
->EnableAutoDepthStencil
)
7151 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
7153 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
7155 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
7157 if(pPresentationParameters
->Windowed
) {
7158 mode
.Width
= swapchain
->orig_width
;
7159 mode
.Height
= swapchain
->orig_height
;
7160 mode
.RefreshRate
= 0;
7161 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7163 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7164 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7165 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7166 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7169 /* Should Width == 800 && Height == 0 set 800x600? */
7170 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7171 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7172 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7179 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
7180 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
7184 if(!pPresentationParameters
->Windowed
) {
7185 DisplayModeChanged
= TRUE
;
7187 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7188 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7190 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7191 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7192 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7194 if(This
->auto_depth_stencil_buffer
) {
7195 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7199 /* Now set the new viewport */
7200 IWineD3DDevice_SetViewport(iface
, &vp
);
7203 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7204 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7205 DisplayModeChanged
) {
7207 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7209 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
7210 if(swapchain
->presentParms
.Windowed
) {
7211 /* switch from windowed to fs */
7212 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7213 pPresentationParameters
->BackBufferWidth
,
7214 pPresentationParameters
->BackBufferHeight
);
7216 /* Fullscreen -> fullscreen mode change */
7217 MoveWindow(swapchain
->win_handle
, 0, 0,
7218 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
7221 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
7222 /* Fullscreen -> windowed switch */
7223 IWineD3DDeviceImpl_RestoreWindow(iface
, swapchain
->win_handle
);
7225 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7226 } else if(!pPresentationParameters
->Windowed
) {
7227 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7228 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7229 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7230 * Reset to clear up their mess. Guild Wars also loses the device during that.
7234 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7235 pPresentationParameters
->BackBufferWidth
,
7236 pPresentationParameters
->BackBufferHeight
);
7237 This
->style
= style
;
7238 This
->exStyle
= exStyle
;
7241 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7243 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7246 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
7247 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7249 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7255 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7256 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7257 /** FIXME: always true at the moment **/
7258 if(!bEnableDialogs
) {
7259 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7265 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7266 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7267 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7269 *pParameters
= This
->createParms
;
7273 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7274 IWineD3DSwapChain
*swapchain
;
7276 TRACE("Relaying to swapchain\n");
7278 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7279 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
7280 IWineD3DSwapChain_Release(swapchain
);
7285 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7286 IWineD3DSwapChain
*swapchain
;
7288 TRACE("Relaying to swapchain\n");
7290 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7291 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7292 IWineD3DSwapChain_Release(swapchain
);
7298 /** ********************************************************
7299 * Notification functions
7300 ** ********************************************************/
7301 /** This function must be called in the release of a resource when ref == 0,
7302 * the contents of resource must still be correct,
7303 * any handles to other resource held by the caller must be closed
7304 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7305 *****************************************************/
7306 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7307 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7309 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7310 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7313 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7316 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7318 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7322 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7323 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7324 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
7327 TRACE("(%p) : resource %p\n", This
, resource
);
7329 context_resource_released(iface
, resource
, type
);
7332 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7333 case WINED3DRTYPE_SURFACE
: {
7336 /* Cleanup any FBO attachments if d3d is enabled */
7337 if(This
->d3d_initialized
) {
7338 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7339 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7341 TRACE("Last active render target destroyed\n");
7342 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7343 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7344 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7345 * and the lastActiveRenderTarget member shouldn't matter
7348 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7349 TRACE("Activating primary back buffer\n");
7350 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7351 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7352 /* Single buffering environment */
7353 TRACE("Activating primary front buffer\n");
7354 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7356 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7357 /* Implicit render target destroyed, that means the device is being destroyed
7358 * whatever we set here, it shouldn't matter
7360 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7363 /* May happen during ddraw uninitialization */
7364 TRACE("Render target set, but swapchain does not exist!\n");
7365 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7369 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7370 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
7371 This
->render_targets
[i
] = NULL
;
7374 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
7375 This
->stencilBufferTarget
= NULL
;
7381 case WINED3DRTYPE_TEXTURE
:
7382 case WINED3DRTYPE_CUBETEXTURE
:
7383 case WINED3DRTYPE_VOLUMETEXTURE
:
7384 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7385 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7386 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7387 This
->stateBlock
->textures
[counter
] = NULL
;
7389 if (This
->updateStateBlock
!= This
->stateBlock
){
7390 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7391 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7392 This
->updateStateBlock
->textures
[counter
] = NULL
;
7397 case WINED3DRTYPE_VOLUME
:
7398 /* TODO: nothing really? */
7400 case WINED3DRTYPE_VERTEXBUFFER
:
7401 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7404 TRACE("Cleaning up stream pointers\n");
7406 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7407 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7408 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7410 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7411 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7412 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7413 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7414 /* Set changed flag? */
7417 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) */
7418 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7419 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7420 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7426 case WINED3DRTYPE_INDEXBUFFER
:
7427 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7428 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7429 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7430 This
->updateStateBlock
->pIndexData
= NULL
;
7433 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7434 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7435 This
->stateBlock
->pIndexData
= NULL
;
7441 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7446 /* Remove the resource from the resourceStore */
7447 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7449 TRACE("Resource released\n");
7453 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7454 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7455 IWineD3DResourceImpl
*resource
, *cursor
;
7457 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7459 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7460 TRACE("enumerating resource %p\n", resource
);
7461 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7462 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7463 if(ret
== S_FALSE
) {
7464 TRACE("Canceling enumeration\n");
7471 /**********************************************************
7472 * IWineD3DDevice VTbl follows
7473 **********************************************************/
7475 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7477 /*** IUnknown methods ***/
7478 IWineD3DDeviceImpl_QueryInterface
,
7479 IWineD3DDeviceImpl_AddRef
,
7480 IWineD3DDeviceImpl_Release
,
7481 /*** IWineD3DDevice methods ***/
7482 IWineD3DDeviceImpl_GetParent
,
7483 /*** Creation methods**/
7484 IWineD3DDeviceImpl_CreateVertexBuffer
,
7485 IWineD3DDeviceImpl_CreateIndexBuffer
,
7486 IWineD3DDeviceImpl_CreateStateBlock
,
7487 IWineD3DDeviceImpl_CreateSurface
,
7488 IWineD3DDeviceImpl_CreateTexture
,
7489 IWineD3DDeviceImpl_CreateVolumeTexture
,
7490 IWineD3DDeviceImpl_CreateVolume
,
7491 IWineD3DDeviceImpl_CreateCubeTexture
,
7492 IWineD3DDeviceImpl_CreateQuery
,
7493 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7494 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7495 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7496 IWineD3DDeviceImpl_CreateVertexShader
,
7497 IWineD3DDeviceImpl_CreatePixelShader
,
7498 IWineD3DDeviceImpl_CreatePalette
,
7499 /*** Odd functions **/
7500 IWineD3DDeviceImpl_Init3D
,
7501 IWineD3DDeviceImpl_InitGDI
,
7502 IWineD3DDeviceImpl_Uninit3D
,
7503 IWineD3DDeviceImpl_UninitGDI
,
7504 IWineD3DDeviceImpl_SetMultithreaded
,
7505 IWineD3DDeviceImpl_EvictManagedResources
,
7506 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7507 IWineD3DDeviceImpl_GetBackBuffer
,
7508 IWineD3DDeviceImpl_GetCreationParameters
,
7509 IWineD3DDeviceImpl_GetDeviceCaps
,
7510 IWineD3DDeviceImpl_GetDirect3D
,
7511 IWineD3DDeviceImpl_GetDisplayMode
,
7512 IWineD3DDeviceImpl_SetDisplayMode
,
7513 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7514 IWineD3DDeviceImpl_GetRasterStatus
,
7515 IWineD3DDeviceImpl_GetSwapChain
,
7516 IWineD3DDeviceImpl_Reset
,
7517 IWineD3DDeviceImpl_SetDialogBoxMode
,
7518 IWineD3DDeviceImpl_SetCursorProperties
,
7519 IWineD3DDeviceImpl_SetCursorPosition
,
7520 IWineD3DDeviceImpl_ShowCursor
,
7521 IWineD3DDeviceImpl_TestCooperativeLevel
,
7522 /*** Getters and setters **/
7523 IWineD3DDeviceImpl_SetClipPlane
,
7524 IWineD3DDeviceImpl_GetClipPlane
,
7525 IWineD3DDeviceImpl_SetClipStatus
,
7526 IWineD3DDeviceImpl_GetClipStatus
,
7527 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7528 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7529 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7530 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7531 IWineD3DDeviceImpl_SetFVF
,
7532 IWineD3DDeviceImpl_GetFVF
,
7533 IWineD3DDeviceImpl_SetGammaRamp
,
7534 IWineD3DDeviceImpl_GetGammaRamp
,
7535 IWineD3DDeviceImpl_SetIndices
,
7536 IWineD3DDeviceImpl_GetIndices
,
7537 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7538 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7539 IWineD3DDeviceImpl_SetLight
,
7540 IWineD3DDeviceImpl_GetLight
,
7541 IWineD3DDeviceImpl_SetLightEnable
,
7542 IWineD3DDeviceImpl_GetLightEnable
,
7543 IWineD3DDeviceImpl_SetMaterial
,
7544 IWineD3DDeviceImpl_GetMaterial
,
7545 IWineD3DDeviceImpl_SetNPatchMode
,
7546 IWineD3DDeviceImpl_GetNPatchMode
,
7547 IWineD3DDeviceImpl_SetPaletteEntries
,
7548 IWineD3DDeviceImpl_GetPaletteEntries
,
7549 IWineD3DDeviceImpl_SetPixelShader
,
7550 IWineD3DDeviceImpl_GetPixelShader
,
7551 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7552 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7553 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7554 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7555 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7556 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7557 IWineD3DDeviceImpl_SetRenderState
,
7558 IWineD3DDeviceImpl_GetRenderState
,
7559 IWineD3DDeviceImpl_SetRenderTarget
,
7560 IWineD3DDeviceImpl_GetRenderTarget
,
7561 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7562 IWineD3DDeviceImpl_SetSamplerState
,
7563 IWineD3DDeviceImpl_GetSamplerState
,
7564 IWineD3DDeviceImpl_SetScissorRect
,
7565 IWineD3DDeviceImpl_GetScissorRect
,
7566 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7567 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7568 IWineD3DDeviceImpl_SetStreamSource
,
7569 IWineD3DDeviceImpl_GetStreamSource
,
7570 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7571 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7572 IWineD3DDeviceImpl_SetTexture
,
7573 IWineD3DDeviceImpl_GetTexture
,
7574 IWineD3DDeviceImpl_SetTextureStageState
,
7575 IWineD3DDeviceImpl_GetTextureStageState
,
7576 IWineD3DDeviceImpl_SetTransform
,
7577 IWineD3DDeviceImpl_GetTransform
,
7578 IWineD3DDeviceImpl_SetVertexDeclaration
,
7579 IWineD3DDeviceImpl_GetVertexDeclaration
,
7580 IWineD3DDeviceImpl_SetVertexShader
,
7581 IWineD3DDeviceImpl_GetVertexShader
,
7582 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7583 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7584 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7585 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7586 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7587 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7588 IWineD3DDeviceImpl_SetViewport
,
7589 IWineD3DDeviceImpl_GetViewport
,
7590 IWineD3DDeviceImpl_MultiplyTransform
,
7591 IWineD3DDeviceImpl_ValidateDevice
,
7592 IWineD3DDeviceImpl_ProcessVertices
,
7593 /*** State block ***/
7594 IWineD3DDeviceImpl_BeginStateBlock
,
7595 IWineD3DDeviceImpl_EndStateBlock
,
7596 /*** Scene management ***/
7597 IWineD3DDeviceImpl_BeginScene
,
7598 IWineD3DDeviceImpl_EndScene
,
7599 IWineD3DDeviceImpl_Present
,
7600 IWineD3DDeviceImpl_Clear
,
7602 IWineD3DDeviceImpl_DrawPrimitive
,
7603 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7604 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7605 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7606 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7607 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7608 IWineD3DDeviceImpl_DrawRectPatch
,
7609 IWineD3DDeviceImpl_DrawTriPatch
,
7610 IWineD3DDeviceImpl_DeletePatch
,
7611 IWineD3DDeviceImpl_ColorFill
,
7612 IWineD3DDeviceImpl_UpdateTexture
,
7613 IWineD3DDeviceImpl_UpdateSurface
,
7614 IWineD3DDeviceImpl_GetFrontBufferData
,
7615 /*** object tracking ***/
7616 IWineD3DDeviceImpl_ResourceReleased
,
7617 IWineD3DDeviceImpl_EnumResources
7620 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl
=
7622 /*** IUnknown methods ***/
7623 IWineD3DDeviceImpl_QueryInterface
,
7624 IWineD3DDeviceImpl_AddRef
,
7625 IWineD3DDeviceImpl_Release
,
7626 /*** IWineD3DDevice methods ***/
7627 IWineD3DDeviceImpl_GetParent
,
7628 /*** Creation methods**/
7629 IWineD3DDeviceImpl_CreateVertexBuffer
,
7630 IWineD3DDeviceImpl_CreateIndexBuffer
,
7631 IWineD3DDeviceImpl_CreateStateBlock
,
7632 IWineD3DDeviceImpl_CreateSurface
,
7633 IWineD3DDeviceImpl_CreateTexture
,
7634 IWineD3DDeviceImpl_CreateVolumeTexture
,
7635 IWineD3DDeviceImpl_CreateVolume
,
7636 IWineD3DDeviceImpl_CreateCubeTexture
,
7637 IWineD3DDeviceImpl_CreateQuery
,
7638 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7639 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7640 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7641 IWineD3DDeviceImpl_CreateVertexShader
,
7642 IWineD3DDeviceImpl_CreatePixelShader
,
7643 IWineD3DDeviceImpl_CreatePalette
,
7644 /*** Odd functions **/
7645 IWineD3DDeviceImpl_Init3D
,
7646 IWineD3DDeviceImpl_InitGDI
,
7647 IWineD3DDeviceImpl_Uninit3D
,
7648 IWineD3DDeviceImpl_UninitGDI
,
7649 IWineD3DDeviceImpl_SetMultithreaded
,
7650 IWineD3DDeviceImpl_EvictManagedResources
,
7651 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7652 IWineD3DDeviceImpl_GetBackBuffer
,
7653 IWineD3DDeviceImpl_GetCreationParameters
,
7654 IWineD3DDeviceImpl_GetDeviceCaps
,
7655 IWineD3DDeviceImpl_GetDirect3D
,
7656 IWineD3DDeviceImpl_GetDisplayMode
,
7657 IWineD3DDeviceImpl_SetDisplayMode
,
7658 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7659 IWineD3DDeviceImpl_GetRasterStatus
,
7660 IWineD3DDeviceImpl_GetSwapChain
,
7661 IWineD3DDeviceImpl_Reset
,
7662 IWineD3DDeviceImpl_SetDialogBoxMode
,
7663 IWineD3DDeviceImpl_SetCursorProperties
,
7664 IWineD3DDeviceImpl_SetCursorPosition
,
7665 IWineD3DDeviceImpl_ShowCursor
,
7666 IWineD3DDeviceImpl_TestCooperativeLevel
,
7667 /*** Getters and setters **/
7668 IWineD3DDeviceImpl_SetClipPlane
,
7669 IWineD3DDeviceImpl_GetClipPlane
,
7670 IWineD3DDeviceImpl_SetClipStatus
,
7671 IWineD3DDeviceImpl_GetClipStatus
,
7672 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7673 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7674 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7675 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7676 IWineD3DDeviceImpl_SetFVF
,
7677 IWineD3DDeviceImpl_GetFVF
,
7678 IWineD3DDeviceImpl_SetGammaRamp
,
7679 IWineD3DDeviceImpl_GetGammaRamp
,
7680 IWineD3DDeviceImpl_SetIndices
,
7681 IWineD3DDeviceImpl_GetIndices
,
7682 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7683 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7684 IWineD3DDeviceImpl_SetLight
,
7685 IWineD3DDeviceImpl_GetLight
,
7686 IWineD3DDeviceImpl_SetLightEnable
,
7687 IWineD3DDeviceImpl_GetLightEnable
,
7688 IWineD3DDeviceImpl_SetMaterial
,
7689 IWineD3DDeviceImpl_GetMaterial
,
7690 IWineD3DDeviceImpl_SetNPatchMode
,
7691 IWineD3DDeviceImpl_GetNPatchMode
,
7692 IWineD3DDeviceImpl_SetPaletteEntries
,
7693 IWineD3DDeviceImpl_GetPaletteEntries
,
7694 IWineD3DDeviceImpl_SetPixelShader
,
7695 IWineD3DDeviceImpl_GetPixelShader
,
7696 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7697 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7698 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7699 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7700 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst
,
7701 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7702 IWineD3DDeviceImpl_SetRenderState
,
7703 IWineD3DDeviceImpl_GetRenderState
,
7704 IWineD3DDeviceImpl_SetRenderTarget
,
7705 IWineD3DDeviceImpl_GetRenderTarget
,
7706 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7707 IWineD3DDeviceImpl_SetSamplerState
,
7708 IWineD3DDeviceImpl_GetSamplerState
,
7709 IWineD3DDeviceImpl_SetScissorRect
,
7710 IWineD3DDeviceImpl_GetScissorRect
,
7711 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7712 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7713 IWineD3DDeviceImpl_SetStreamSource
,
7714 IWineD3DDeviceImpl_GetStreamSource
,
7715 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7716 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7717 IWineD3DDeviceImpl_SetTexture
,
7718 IWineD3DDeviceImpl_GetTexture
,
7719 IWineD3DDeviceImpl_SetTextureStageState
,
7720 IWineD3DDeviceImpl_GetTextureStageState
,
7721 IWineD3DDeviceImpl_SetTransform
,
7722 IWineD3DDeviceImpl_GetTransform
,
7723 IWineD3DDeviceImpl_SetVertexDeclaration
,
7724 IWineD3DDeviceImpl_GetVertexDeclaration
,
7725 IWineD3DDeviceImpl_SetVertexShader
,
7726 IWineD3DDeviceImpl_GetVertexShader
,
7727 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7728 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7729 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7730 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7731 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst
,
7732 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7733 IWineD3DDeviceImpl_SetViewport
,
7734 IWineD3DDeviceImpl_GetViewport
,
7735 IWineD3DDeviceImpl_MultiplyTransform
,
7736 IWineD3DDeviceImpl_ValidateDevice
,
7737 IWineD3DDeviceImpl_ProcessVertices
,
7738 /*** State block ***/
7739 IWineD3DDeviceImpl_BeginStateBlock
,
7740 IWineD3DDeviceImpl_EndStateBlock
,
7741 /*** Scene management ***/
7742 IWineD3DDeviceImpl_BeginScene
,
7743 IWineD3DDeviceImpl_EndScene
,
7744 IWineD3DDeviceImpl_Present
,
7745 IWineD3DDeviceImpl_Clear
,
7747 IWineD3DDeviceImpl_DrawPrimitive
,
7748 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7749 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7750 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7751 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7752 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7753 IWineD3DDeviceImpl_DrawRectPatch
,
7754 IWineD3DDeviceImpl_DrawTriPatch
,
7755 IWineD3DDeviceImpl_DeletePatch
,
7756 IWineD3DDeviceImpl_ColorFill
,
7757 IWineD3DDeviceImpl_UpdateTexture
,
7758 IWineD3DDeviceImpl_UpdateSurface
,
7759 IWineD3DDeviceImpl_GetFrontBufferData
,
7760 /*** object tracking ***/
7761 IWineD3DDeviceImpl_ResourceReleased
,
7762 IWineD3DDeviceImpl_EnumResources
7765 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7766 WINED3DRS_ALPHABLENDENABLE
,
7767 WINED3DRS_ALPHAFUNC
,
7768 WINED3DRS_ALPHAREF
,
7769 WINED3DRS_ALPHATESTENABLE
,
7771 WINED3DRS_COLORWRITEENABLE
,
7772 WINED3DRS_DESTBLEND
,
7773 WINED3DRS_DITHERENABLE
,
7774 WINED3DRS_FILLMODE
,
7775 WINED3DRS_FOGDENSITY
,
7777 WINED3DRS_FOGSTART
,
7778 WINED3DRS_LASTPIXEL
,
7779 WINED3DRS_SHADEMODE
,
7780 WINED3DRS_SRCBLEND
,
7781 WINED3DRS_STENCILENABLE
,
7782 WINED3DRS_STENCILFAIL
,
7783 WINED3DRS_STENCILFUNC
,
7784 WINED3DRS_STENCILMASK
,
7785 WINED3DRS_STENCILPASS
,
7786 WINED3DRS_STENCILREF
,
7787 WINED3DRS_STENCILWRITEMASK
,
7788 WINED3DRS_STENCILZFAIL
,
7789 WINED3DRS_TEXTUREFACTOR
,
7800 WINED3DRS_ZWRITEENABLE
7803 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7804 WINED3DTSS_ADDRESSW
,
7805 WINED3DTSS_ALPHAARG0
,
7806 WINED3DTSS_ALPHAARG1
,
7807 WINED3DTSS_ALPHAARG2
,
7808 WINED3DTSS_ALPHAOP
,
7809 WINED3DTSS_BUMPENVLOFFSET
,
7810 WINED3DTSS_BUMPENVLSCALE
,
7811 WINED3DTSS_BUMPENVMAT00
,
7812 WINED3DTSS_BUMPENVMAT01
,
7813 WINED3DTSS_BUMPENVMAT10
,
7814 WINED3DTSS_BUMPENVMAT11
,
7815 WINED3DTSS_COLORARG0
,
7816 WINED3DTSS_COLORARG1
,
7817 WINED3DTSS_COLORARG2
,
7818 WINED3DTSS_COLOROP
,
7819 WINED3DTSS_RESULTARG
,
7820 WINED3DTSS_TEXCOORDINDEX
,
7821 WINED3DTSS_TEXTURETRANSFORMFLAGS
7824 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7825 WINED3DSAMP_ADDRESSU
,
7826 WINED3DSAMP_ADDRESSV
,
7827 WINED3DSAMP_ADDRESSW
,
7828 WINED3DSAMP_BORDERCOLOR
,
7829 WINED3DSAMP_MAGFILTER
,
7830 WINED3DSAMP_MINFILTER
,
7831 WINED3DSAMP_MIPFILTER
,
7832 WINED3DSAMP_MIPMAPLODBIAS
,
7833 WINED3DSAMP_MAXMIPLEVEL
,
7834 WINED3DSAMP_MAXANISOTROPY
,
7835 WINED3DSAMP_SRGBTEXTURE
,
7836 WINED3DSAMP_ELEMENTINDEX
7839 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7841 WINED3DRS_AMBIENTMATERIALSOURCE
,
7842 WINED3DRS_CLIPPING
,
7843 WINED3DRS_CLIPPLANEENABLE
,
7844 WINED3DRS_COLORVERTEX
,
7845 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7846 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7847 WINED3DRS_FOGDENSITY
,
7849 WINED3DRS_FOGSTART
,
7850 WINED3DRS_FOGTABLEMODE
,
7851 WINED3DRS_FOGVERTEXMODE
,
7852 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7853 WINED3DRS_LIGHTING
,
7854 WINED3DRS_LOCALVIEWER
,
7855 WINED3DRS_MULTISAMPLEANTIALIAS
,
7856 WINED3DRS_MULTISAMPLEMASK
,
7857 WINED3DRS_NORMALIZENORMALS
,
7858 WINED3DRS_PATCHEDGESTYLE
,
7859 WINED3DRS_POINTSCALE_A
,
7860 WINED3DRS_POINTSCALE_B
,
7861 WINED3DRS_POINTSCALE_C
,
7862 WINED3DRS_POINTSCALEENABLE
,
7863 WINED3DRS_POINTSIZE
,
7864 WINED3DRS_POINTSIZE_MAX
,
7865 WINED3DRS_POINTSIZE_MIN
,
7866 WINED3DRS_POINTSPRITEENABLE
,
7867 WINED3DRS_RANGEFOGENABLE
,
7868 WINED3DRS_SPECULARMATERIALSOURCE
,
7869 WINED3DRS_TWEENFACTOR
,
7870 WINED3DRS_VERTEXBLEND
,
7871 WINED3DRS_CULLMODE
,
7875 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7876 WINED3DTSS_TEXCOORDINDEX
,
7877 WINED3DTSS_TEXTURETRANSFORMFLAGS
7880 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7881 WINED3DSAMP_DMAPOFFSET
7884 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7885 DWORD rep
= This
->StateTable
[state
].representative
;
7889 WineD3DContext
*context
;
7892 for(i
= 0; i
< This
->numContexts
; i
++) {
7893 context
= This
->contexts
[i
];
7894 if(isStateDirty(context
, rep
)) continue;
7896 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7899 context
->isStateDirty
[idx
] |= (1 << shift
);
7903 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7904 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7905 /* The drawable size of a pbuffer render target is the current pbuffer size
7907 *width
= dev
->pbufferWidth
;
7908 *height
= dev
->pbufferHeight
;
7911 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7912 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7914 *width
= This
->pow2Width
;
7915 *height
= This
->pow2Height
;
7918 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7919 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7920 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7921 * current context's drawable, which is the size of the back buffer of the swapchain
7922 * the active context belongs to. The back buffer of the swapchain is stored as the
7923 * surface the context belongs to.
7925 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
7926 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;