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
;
826 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
827 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
828 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
829 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
831 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
832 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
833 object
->baseTexture
.pow2Matrix
[10] = 1.0;
834 object
->baseTexture
.pow2Matrix
[15] = 1.0;
835 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
836 object
->cond_np2
= TRUE
;
837 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
839 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
840 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
841 object
->baseTexture
.pow2Matrix
[10] = 1.0;
842 object
->baseTexture
.pow2Matrix
[15] = 1.0;
843 object
->target
= GL_TEXTURE_2D
;
844 object
->cond_np2
= FALSE
;
846 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
848 /* Calculate levels for mip mapping */
849 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
850 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
851 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
852 return WINED3DERR_INVALIDCALL
;
855 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
856 return WINED3DERR_INVALIDCALL
;
858 object
->baseTexture
.levels
= 1;
859 } else if (Levels
== 0) {
860 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
861 object
->baseTexture
.levels
++;
864 while (tmpW
> 1 || tmpH
> 1) {
865 tmpW
= max(1, tmpW
>> 1);
866 tmpH
= max(1, tmpH
>> 1);
867 object
->baseTexture
.levels
++;
869 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
872 /* Generate all the surfaces */
875 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
877 /* use the callback to create the texture surface */
878 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
879 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
880 FIXME("Failed to create surface %p\n", object
);
882 object
->surfaces
[i
] = NULL
;
883 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
889 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
890 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
891 surface_set_texture_target(object
->surfaces
[i
], object
->target
);
892 /* calculate the next mipmap level */
893 tmpW
= max(1, tmpW
>> 1);
894 tmpH
= max(1, tmpH
>> 1);
896 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
898 TRACE("(%p) : Created texture %p\n", This
, object
);
902 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
903 UINT Width
, UINT Height
, UINT Depth
,
904 UINT Levels
, DWORD Usage
,
905 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
906 IWineD3DVolumeTexture
**ppVolumeTexture
,
907 HANDLE
*pSharedHandle
, IUnknown
*parent
,
908 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
910 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
911 IWineD3DVolumeTextureImpl
*object
;
916 const GlPixelFormatDesc
*glDesc
;
918 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
920 /* TODO: It should only be possible to create textures for formats
921 that are reported as supported */
922 if (WINED3DFMT_UNKNOWN
>= Format
) {
923 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
924 return WINED3DERR_INVALIDCALL
;
926 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
927 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
928 return WINED3DERR_INVALIDCALL
;
931 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
932 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
934 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
935 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
937 object
->width
= Width
;
938 object
->height
= Height
;
939 object
->depth
= Depth
;
941 /* Is NP2 support for volumes needed? */
942 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
943 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
944 object
->baseTexture
.pow2Matrix
[10] = 1.0;
945 object
->baseTexture
.pow2Matrix
[15] = 1.0;
947 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
948 object
->baseTexture
.minMipLookup
= &minMipLookup
;
949 object
->baseTexture
.magLookup
= &magLookup
;
951 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
952 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
955 /* Calculate levels for mip mapping */
956 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
957 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
958 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
959 return WINED3DERR_INVALIDCALL
;
962 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
963 return WINED3DERR_INVALIDCALL
;
966 } else if (Levels
== 0) {
967 object
->baseTexture
.levels
++;
971 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
972 tmpW
= max(1, tmpW
>> 1);
973 tmpH
= max(1, tmpH
>> 1);
974 tmpD
= max(1, tmpD
>> 1);
975 object
->baseTexture
.levels
++;
977 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
980 /* Generate all the surfaces */
985 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
988 /* Create the volume */
989 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
990 &object
->volumes
[i
], pSharedHandle
);
993 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
994 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
995 *ppVolumeTexture
= NULL
;
999 /* Set its container to this object */
1000 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1002 /* calculate the next mipmap level */
1003 tmpW
= max(1, tmpW
>> 1);
1004 tmpH
= max(1, tmpH
>> 1);
1005 tmpD
= max(1, tmpD
>> 1);
1007 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1009 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1010 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1014 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1015 UINT Width
, UINT Height
, UINT Depth
,
1017 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1018 IWineD3DVolume
** ppVolume
,
1019 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1021 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1022 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1023 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1025 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1026 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1027 return WINED3DERR_INVALIDCALL
;
1030 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1032 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1033 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1035 object
->currentDesc
.Width
= Width
;
1036 object
->currentDesc
.Height
= Height
;
1037 object
->currentDesc
.Depth
= Depth
;
1038 object
->bytesPerPixel
= formatDesc
->bpp
;
1040 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1041 object
->lockable
= TRUE
;
1042 object
->locked
= FALSE
;
1043 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1044 object
->dirty
= TRUE
;
1046 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1049 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1050 UINT Levels
, DWORD Usage
,
1051 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1052 IWineD3DCubeTexture
**ppCubeTexture
,
1053 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1054 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1056 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1057 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1061 unsigned int pow2EdgeLength
= EdgeLength
;
1062 const GlPixelFormatDesc
*glDesc
;
1063 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1065 /* TODO: It should only be possible to create textures for formats
1066 that are reported as supported */
1067 if (WINED3DFMT_UNKNOWN
>= Format
) {
1068 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1069 return WINED3DERR_INVALIDCALL
;
1072 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1073 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1074 return WINED3DERR_INVALIDCALL
;
1077 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1078 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1080 TRACE("(%p) Create Cube Texture\n", This
);
1082 /** Non-power2 support **/
1084 /* Find the nearest pow2 match */
1086 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1088 object
->edgeLength
= EdgeLength
;
1089 /* TODO: support for native non-power 2 */
1090 /* Precalculated scaling for 'faked' non power of two texture coords */
1091 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1092 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1093 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1094 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1096 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
1097 object
->baseTexture
.minMipLookup
= &minMipLookup
;
1098 object
->baseTexture
.magLookup
= &magLookup
;
1100 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
1101 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
1104 /* Calculate levels for mip mapping */
1105 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1106 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1107 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1108 HeapFree(GetProcessHeap(), 0, object
);
1109 *ppCubeTexture
= NULL
;
1111 return WINED3DERR_INVALIDCALL
;
1114 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1115 HeapFree(GetProcessHeap(), 0, object
);
1116 *ppCubeTexture
= NULL
;
1118 return WINED3DERR_INVALIDCALL
;
1121 } else if (Levels
== 0) {
1122 object
->baseTexture
.levels
++;
1125 tmpW
= max(1, tmpW
>> 1);
1126 object
->baseTexture
.levels
++;
1128 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1131 /* Generate all the surfaces */
1133 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1135 /* Create the 6 faces */
1136 for (j
= 0; j
< 6; j
++) {
1137 static const GLenum cube_targets
[6] = {
1138 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
1139 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
1140 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
1141 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
1142 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
1143 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1146 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1147 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1149 if(hr
!= WINED3D_OK
) {
1153 for (l
= 0; l
< j
; l
++) {
1154 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1156 for (k
= 0; k
< i
; k
++) {
1157 for (l
= 0; l
< 6; l
++) {
1158 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1162 FIXME("(%p) Failed to create surface\n",object
);
1163 HeapFree(GetProcessHeap(),0,object
);
1164 *ppCubeTexture
= NULL
;
1167 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1168 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1169 surface_set_texture_target(object
->surfaces
[j
][i
], cube_targets
[j
]);
1171 tmpW
= max(1, tmpW
>> 1);
1173 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1175 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1176 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1180 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1181 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1182 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1183 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1184 const IWineD3DQueryVtbl
*vtable
;
1186 /* Just a check to see if we support this type of query */
1188 case WINED3DQUERYTYPE_OCCLUSION
:
1189 TRACE("(%p) occlusion query\n", This
);
1190 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1193 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1195 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1198 case WINED3DQUERYTYPE_EVENT
:
1199 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1200 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1201 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1203 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1205 vtable
= &IWineD3DEventQuery_Vtbl
;
1209 case WINED3DQUERYTYPE_VCACHE
:
1210 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1211 case WINED3DQUERYTYPE_VERTEXSTATS
:
1212 case WINED3DQUERYTYPE_TIMESTAMP
:
1213 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1214 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1215 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1216 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1217 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1218 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1219 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1220 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1222 /* Use the base Query vtable until we have a special one for each query */
1223 vtable
= &IWineD3DQuery_Vtbl
;
1224 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1226 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1230 D3DCREATEOBJECTINSTANCE(object
, Query
)
1231 object
->lpVtbl
= vtable
;
1232 object
->type
= Type
;
1233 object
->state
= QUERY_CREATED
;
1234 /* allocated the 'extended' data based on the type of query requested */
1236 case WINED3DQUERYTYPE_OCCLUSION
:
1237 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1238 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1240 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1241 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1242 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1245 case WINED3DQUERYTYPE_EVENT
:
1246 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1247 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1249 if(GL_SUPPORT(APPLE_FENCE
)) {
1250 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1251 checkGLcall("glGenFencesAPPLE");
1252 } else if(GL_SUPPORT(NV_FENCE
)) {
1253 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1254 checkGLcall("glGenFencesNV");
1258 case WINED3DQUERYTYPE_VCACHE
:
1259 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1260 case WINED3DQUERYTYPE_VERTEXSTATS
:
1261 case WINED3DQUERYTYPE_TIMESTAMP
:
1262 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1263 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1264 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1265 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1266 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1267 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1268 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1269 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1271 object
->extendedData
= 0;
1272 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1274 TRACE("(%p) : Created Query %p\n", This
, object
);
1278 /*****************************************************************************
1279 * IWineD3DDeviceImpl_SetupFullscreenWindow
1281 * Helper function that modifies a HWND's Style and ExStyle for proper
1285 * iface: Pointer to the IWineD3DDevice interface
1286 * window: Window to setup
1288 *****************************************************************************/
1289 static LONG
fullscreen_style(LONG orig_style
) {
1290 LONG style
= orig_style
;
1291 style
&= ~WS_CAPTION
;
1292 style
&= ~WS_THICKFRAME
;
1294 /* Make sure the window is managed, otherwise we won't get keyboard input */
1295 style
|= WS_POPUP
| WS_SYSMENU
;
1300 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1301 LONG exStyle
= orig_exStyle
;
1303 /* Filter out window decorations */
1304 exStyle
&= ~WS_EX_WINDOWEDGE
;
1305 exStyle
&= ~WS_EX_CLIENTEDGE
;
1310 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
) {
1311 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1313 LONG style
, exStyle
;
1314 /* Don't do anything if an original style is stored.
1315 * That shouldn't happen
1317 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1318 if (This
->style
|| This
->exStyle
) {
1319 ERR("(%p): Want to change the window parameters of HWND %p, but "
1320 "another style is stored for restoration afterwards\n", This
, window
);
1323 /* Get the parameters and save them */
1324 style
= GetWindowLongW(window
, GWL_STYLE
);
1325 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1326 This
->style
= style
;
1327 This
->exStyle
= exStyle
;
1329 style
= fullscreen_style(style
);
1330 exStyle
= fullscreen_exStyle(exStyle
);
1332 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1333 This
->style
, This
->exStyle
, style
, exStyle
);
1335 SetWindowLongW(window
, GWL_STYLE
, style
);
1336 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1338 /* Inform the window about the update. */
1339 SetWindowPos(window
, HWND_TOP
, 0, 0,
1340 w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
);
1343 /*****************************************************************************
1344 * IWineD3DDeviceImpl_RestoreWindow
1346 * Helper function that restores a windows' properties when taking it out
1347 * of fullscreen mode
1350 * iface: Pointer to the IWineD3DDevice interface
1351 * window: Window to setup
1353 *****************************************************************************/
1354 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1355 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1356 LONG style
, exStyle
;
1358 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1359 * switch, do nothing
1361 if (!This
->style
&& !This
->exStyle
) return;
1363 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1364 This
, window
, This
->style
, This
->exStyle
);
1366 style
= GetWindowLongW(window
, GWL_STYLE
);
1367 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1369 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1370 * Some applications change it before calling Reset() when switching between windowed and
1371 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1373 if(style
== fullscreen_style(This
->style
) &&
1374 exStyle
== fullscreen_style(This
->exStyle
)) {
1375 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1376 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1379 /* Delete the old values */
1383 /* Inform the window about the update */
1384 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1385 0, 0, 0, 0, /* Pos, Size, ignored */
1386 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1389 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1390 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1392 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1393 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
,
1394 WINED3DSURFTYPE surface_type
) {
1395 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1398 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1400 IUnknown
*bufferParent
;
1401 BOOL displaymode_set
= FALSE
;
1402 WINED3DDISPLAYMODE Mode
;
1403 const StaticPixelFormatDesc
*formatDesc
;
1405 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1407 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1408 * does a device hold a reference to a swap chain giving them a lifetime of the device
1409 * or does the swap chain notify the device of its destruction.
1410 *******************************/
1412 /* Check the params */
1413 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1414 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1415 return WINED3DERR_INVALIDCALL
;
1416 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1417 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");
1420 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1421 switch(surface_type
) {
1423 object
->lpVtbl
= &IWineGDISwapChain_Vtbl
;
1425 case SURFACE_OPENGL
:
1426 object
->lpVtbl
= &IWineD3DSwapChain_Vtbl
;
1428 case SURFACE_UNKNOWN
:
1429 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1430 return WINED3DERR_INVALIDCALL
;
1433 /*********************
1434 * Lookup the window Handle and the relating X window handle
1435 ********************/
1437 /* Setup hwnd we are using, plus which display this equates to */
1438 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1439 if (!object
->win_handle
) {
1440 object
->win_handle
= This
->createParms
.hFocusWindow
;
1442 if(!pPresentationParameters
->Windowed
&& object
->win_handle
) {
1443 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
,
1444 pPresentationParameters
->BackBufferWidth
,
1445 pPresentationParameters
->BackBufferHeight
);
1448 hDc
= GetDC(object
->win_handle
);
1449 TRACE("Using hDc %p\n", hDc
);
1452 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1453 return WINED3DERR_NOTAVAILABLE
;
1456 /* Get info on the current display setup */
1457 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1458 object
->orig_width
= Mode
.Width
;
1459 object
->orig_height
= Mode
.Height
;
1460 object
->orig_fmt
= Mode
.Format
;
1461 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1463 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1464 * then the corresponding dimension of the client area of the hDeviceWindow
1465 * (or the focus window, if hDeviceWindow is NULL) is taken.
1466 **********************/
1468 if (pPresentationParameters
->Windowed
&&
1469 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1470 (pPresentationParameters
->BackBufferHeight
== 0) ||
1471 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1474 GetClientRect(object
->win_handle
, &Rect
);
1476 if (pPresentationParameters
->BackBufferWidth
== 0) {
1477 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1478 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1480 if (pPresentationParameters
->BackBufferHeight
== 0) {
1481 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1482 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1484 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1485 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1486 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1490 /* Put the correct figures in the presentation parameters */
1491 TRACE("Copying across presentation parameters\n");
1492 object
->presentParms
= *pPresentationParameters
;
1494 TRACE("calling rendertarget CB\n");
1495 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1497 object
->presentParms
.BackBufferWidth
,
1498 object
->presentParms
.BackBufferHeight
,
1499 object
->presentParms
.BackBufferFormat
,
1500 object
->presentParms
.MultiSampleType
,
1501 object
->presentParms
.MultiSampleQuality
,
1502 TRUE
/* Lockable */,
1503 &object
->frontBuffer
,
1504 NULL
/* pShared (always null)*/);
1505 if (SUCCEEDED(hr
)) {
1506 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1507 if(surface_type
== SURFACE_OPENGL
) {
1508 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1511 ERR("Failed to create the front buffer\n");
1515 /*********************
1516 * Windowed / Fullscreen
1517 *******************/
1520 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1521 * so we should really check to see if there is a fullscreen swapchain already
1522 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1523 **************************************/
1525 if (!pPresentationParameters
->Windowed
) {
1526 WINED3DDISPLAYMODE mode
;
1529 /* Change the display settings */
1530 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1531 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1532 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1533 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1535 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1536 displaymode_set
= TRUE
;
1540 * Create an opengl context for the display visual
1541 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1542 * use different properties after that point in time. FIXME: How to handle when requested format
1543 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1544 * it chooses is identical to the one already being used!
1545 **********************************/
1546 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1548 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1549 if(!object
->context
)
1550 return E_OUTOFMEMORY
;
1551 object
->num_contexts
= 1;
1553 if(surface_type
== SURFACE_OPENGL
) {
1554 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1555 if (!object
->context
[0]) {
1556 ERR("Failed to create a new context\n");
1557 hr
= WINED3DERR_NOTAVAILABLE
;
1560 TRACE("Context created (HWND=%p, glContext=%p)\n",
1561 object
->win_handle
, object
->context
[0]->glCtx
);
1565 /*********************
1566 * Create the back, front and stencil buffers
1567 *******************/
1568 if(object
->presentParms
.BackBufferCount
> 0) {
1571 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1572 if(!object
->backBuffer
) {
1573 ERR("Out of memory\n");
1578 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1579 TRACE("calling rendertarget CB\n");
1580 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1582 object
->presentParms
.BackBufferWidth
,
1583 object
->presentParms
.BackBufferHeight
,
1584 object
->presentParms
.BackBufferFormat
,
1585 object
->presentParms
.MultiSampleType
,
1586 object
->presentParms
.MultiSampleQuality
,
1587 TRUE
/* Lockable */,
1588 &object
->backBuffer
[i
],
1589 NULL
/* pShared (always null)*/);
1591 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1593 ERR("Cannot create new back buffer\n");
1596 if(surface_type
== SURFACE_OPENGL
) {
1598 glDrawBuffer(GL_BACK
);
1599 checkGLcall("glDrawBuffer(GL_BACK)");
1604 object
->backBuffer
= NULL
;
1606 /* Single buffering - draw to front buffer */
1607 if(surface_type
== SURFACE_OPENGL
) {
1609 glDrawBuffer(GL_FRONT
);
1610 checkGLcall("glDrawBuffer(GL_FRONT)");
1615 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1616 if (pPresentationParameters
->EnableAutoDepthStencil
&& surface_type
== SURFACE_OPENGL
) {
1617 TRACE("Creating depth stencil buffer\n");
1618 if (This
->auto_depth_stencil_buffer
== NULL
) {
1619 hr
= D3DCB_CreateDepthStencil(This
->parent
,
1621 object
->presentParms
.BackBufferWidth
,
1622 object
->presentParms
.BackBufferHeight
,
1623 object
->presentParms
.AutoDepthStencilFormat
,
1624 object
->presentParms
.MultiSampleType
,
1625 object
->presentParms
.MultiSampleQuality
,
1626 FALSE
/* FIXME: Discard */,
1627 &This
->auto_depth_stencil_buffer
,
1628 NULL
/* pShared (always null)*/ );
1629 if (SUCCEEDED(hr
)) {
1630 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1632 ERR("Failed to create the auto depth stencil\n");
1638 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1640 TRACE("Created swapchain %p\n", object
);
1641 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, pPresentationParameters
->EnableAutoDepthStencil
);
1645 if (displaymode_set
) {
1649 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1652 /* Change the display settings */
1653 memset(&devmode
, 0, sizeof(devmode
));
1654 devmode
.dmSize
= sizeof(devmode
);
1655 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1656 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1657 devmode
.dmPelsWidth
= object
->orig_width
;
1658 devmode
.dmPelsHeight
= object
->orig_height
;
1659 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1662 if (object
->backBuffer
) {
1664 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1665 if(object
->backBuffer
[i
]) {
1666 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1667 IUnknown_Release(bufferParent
); /* once for the get parent */
1668 if (IUnknown_Release(bufferParent
) > 0) {
1669 FIXME("(%p) Something's still holding the back buffer\n",This
);
1673 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1674 object
->backBuffer
= NULL
;
1676 if(object
->context
[0])
1677 DestroyContext(This
, object
->context
[0]);
1678 if(object
->frontBuffer
) {
1679 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1680 IUnknown_Release(bufferParent
); /* once for the get parent */
1681 if (IUnknown_Release(bufferParent
) > 0) {
1682 FIXME("(%p) Something's still holding the front buffer\n",This
);
1685 HeapFree(GetProcessHeap(), 0, object
);
1689 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1690 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1691 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1692 TRACE("(%p)\n", This
);
1694 return This
->NumberOfSwapChains
;
1697 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1698 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1699 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1701 if(iSwapChain
< This
->NumberOfSwapChains
) {
1702 *pSwapChain
= This
->swapchains
[iSwapChain
];
1703 IWineD3DSwapChain_AddRef(*pSwapChain
);
1704 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1707 TRACE("Swapchain out of range\n");
1709 return WINED3DERR_INVALIDCALL
;
1714 * Vertex Declaration
1716 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1717 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
1718 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1719 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1720 HRESULT hr
= WINED3D_OK
;
1722 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1723 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1725 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1727 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1729 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration
*)object
);
1730 *ppVertexDeclaration
= NULL
;
1736 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1737 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1739 unsigned int idx
, idx2
;
1740 unsigned int offset
;
1741 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1742 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1743 BOOL has_blend_idx
= has_blend
&&
1744 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1745 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1746 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1747 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1748 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1749 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1750 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1752 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1753 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1755 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1756 WINED3DVERTEXELEMENT
*elements
= NULL
;
1759 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1760 if (has_blend_idx
) num_blends
--;
1762 /* Compute declaration size */
1763 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1764 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1766 /* convert the declaration */
1767 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1771 elements
[size
-1] = end_element
;
1774 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1775 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1776 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1779 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1780 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1782 elements
[idx
].UsageIndex
= 0;
1785 if (has_blend
&& (num_blends
> 0)) {
1786 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1787 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1789 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1790 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1791 elements
[idx
].UsageIndex
= 0;
1794 if (has_blend_idx
) {
1795 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1796 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1797 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1798 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1799 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1801 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1802 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1803 elements
[idx
].UsageIndex
= 0;
1807 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1808 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1809 elements
[idx
].UsageIndex
= 0;
1813 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1814 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1815 elements
[idx
].UsageIndex
= 0;
1819 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1820 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1821 elements
[idx
].UsageIndex
= 0;
1825 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1826 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1827 elements
[idx
].UsageIndex
= 1;
1830 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1831 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1832 switch (numcoords
) {
1833 case WINED3DFVF_TEXTUREFORMAT1
:
1834 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1836 case WINED3DFVF_TEXTUREFORMAT2
:
1837 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1839 case WINED3DFVF_TEXTUREFORMAT3
:
1840 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1842 case WINED3DFVF_TEXTUREFORMAT4
:
1843 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1846 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1847 elements
[idx
].UsageIndex
= idx2
;
1851 /* Now compute offsets, and initialize the rest of the fields */
1852 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1853 elements
[idx
].Stream
= 0;
1854 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1855 elements
[idx
].Offset
= offset
;
1856 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1859 *ppVertexElements
= elements
;
1863 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1864 WINED3DVERTEXELEMENT
* elements
= NULL
;
1865 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1869 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1870 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1872 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1873 HeapFree(GetProcessHeap(), 0, elements
);
1874 if (hr
!= S_OK
) return hr
;
1879 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1880 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1881 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1882 HRESULT hr
= WINED3D_OK
;
1883 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1884 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1886 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1888 if (vertex_declaration
) {
1889 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1892 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1894 if (WINED3D_OK
!= hr
) {
1895 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1896 IWineD3DVertexShader_Release(*ppVertexShader
);
1897 return WINED3DERR_INVALIDCALL
;
1899 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1904 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1905 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1906 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1907 HRESULT hr
= WINED3D_OK
;
1909 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1910 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1911 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1912 if (WINED3D_OK
== hr
) {
1913 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1914 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1916 WARN("(%p) : Failed to create pixel shader\n", This
);
1922 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1923 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1924 IWineD3DPaletteImpl
*object
;
1926 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1928 /* Create the new object */
1929 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1931 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1932 return E_OUTOFMEMORY
;
1935 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1937 object
->Flags
= Flags
;
1938 object
->parent
= Parent
;
1939 object
->wineD3DDevice
= This
;
1940 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1942 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1945 HeapFree( GetProcessHeap(), 0, object
);
1946 return E_OUTOFMEMORY
;
1949 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1951 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1955 *Palette
= (IWineD3DPalette
*) object
;
1960 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1964 HDC dcb
= NULL
, dcs
= NULL
;
1965 WINEDDCOLORKEY colorkey
;
1967 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1970 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1971 dcb
= CreateCompatibleDC(NULL
);
1973 SelectObject(dcb
, hbm
);
1977 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1978 * couldn't be loaded
1980 memset(&bm
, 0, sizeof(bm
));
1985 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1986 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1987 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1989 ERR("Wine logo requested, but failed to create surface\n");
1994 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1995 if(FAILED(hr
)) goto out
;
1996 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1997 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1999 colorkey
.dwColorSpaceLowValue
= 0;
2000 colorkey
.dwColorSpaceHighValue
= 0;
2001 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
2003 /* Fill the surface with a white color to show that wined3d is there */
2004 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2017 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
2019 /* Under DirectX you can have texture stage operations even if no texture is
2020 bound, whereas opengl will only do texture operations when a valid texture is
2021 bound. We emulate this by creating dummy textures and binding them to each
2022 texture stage, but disable all stages by default. Hence if a stage is enabled
2023 then the default texture will kick in until replaced by a SetTexture call */
2026 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2027 /* The dummy texture does not have client storage backing */
2028 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2029 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2031 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2032 GLubyte white
= 255;
2034 /* Make appropriate texture active */
2035 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2036 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2037 checkGLcall("glActiveTextureARB");
2039 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2042 /* Generate an opengl texture name */
2043 glGenTextures(1, &This
->dummyTextureName
[i
]);
2044 checkGLcall("glGenTextures");
2045 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2047 /* Generate a dummy 2d texture (not using 1d because they cause many
2048 * DRI drivers fall back to sw) */
2049 This
->stateBlock
->textureDimensions
[i
] = GL_TEXTURE_2D
;
2050 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2051 checkGLcall("glBindTexture");
2053 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2054 checkGLcall("glTexImage2D");
2056 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2057 /* Reenable because if supported it is enabled by default */
2058 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2059 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2065 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2066 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2067 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2072 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
2073 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2074 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2076 /* TODO: Test if OpenGL is compiled in and loaded */
2078 TRACE("(%p) : Creating stateblock\n", This
);
2079 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2080 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2082 (IWineD3DStateBlock
**)&This
->stateBlock
,
2084 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2085 WARN("Failed to create stateblock\n");
2088 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2089 This
->updateStateBlock
= This
->stateBlock
;
2090 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2092 hr
= allocate_shader_constants(This
->updateStateBlock
);
2093 if (WINED3D_OK
!= hr
) {
2097 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2098 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2100 This
->NumberOfPalettes
= 1;
2101 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
2102 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
2103 ERR("Out of memory!\n");
2106 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2107 if(!This
->palettes
[0]) {
2108 ERR("Out of memory!\n");
2111 for (i
= 0; i
< 256; ++i
) {
2112 This
->palettes
[0][i
].peRed
= 0xFF;
2113 This
->palettes
[0][i
].peGreen
= 0xFF;
2114 This
->palettes
[0][i
].peBlue
= 0xFF;
2115 This
->palettes
[0][i
].peFlags
= 0xFF;
2117 This
->currentPalette
= 0;
2119 /* Initialize the texture unit mapping to a 1:1 mapping */
2120 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2121 if (state
< GL_LIMITS(fragment_samplers
)) {
2122 This
->texUnitMap
[state
] = state
;
2123 This
->rev_tex_unit_map
[state
] = state
;
2125 This
->texUnitMap
[state
] = -1;
2126 This
->rev_tex_unit_map
[state
] = -1;
2130 /* Setup the implicit swapchain */
2131 TRACE("Creating implicit swapchain\n");
2132 hr
=D3DCB_CreateAdditionalSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2133 if (FAILED(hr
) || !swapchain
) {
2134 WARN("Failed to create implicit swapchain\n");
2138 This
->NumberOfSwapChains
= 1;
2139 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2140 if(!This
->swapchains
) {
2141 ERR("Out of memory!\n");
2144 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2146 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2147 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2148 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2149 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2152 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2153 This
->render_targets
[0] = swapchain
->frontBuffer
;
2154 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2156 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2157 This
->activeContext
= swapchain
->context
[0];
2158 This
->lastThread
= GetCurrentThreadId();
2160 /* Depth Stencil support */
2161 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2162 if (NULL
!= This
->stencilBufferTarget
) {
2163 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2166 hr
= This
->shader_backend
->shader_alloc_private(iface
);
2168 TRACE("Shader private data couldn't be allocated\n");
2171 hr
= This
->frag_pipe
->alloc_private(iface
);
2173 TRACE("Fragment pipeline private data couldn't be allocated\n");
2176 hr
= This
->blitter
->alloc_private(iface
);
2178 TRACE("Blitter private data couldn't be allocated\n");
2182 /* Set up some starting GL setup */
2184 /* Setup all the devices defaults */
2185 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2186 create_dummy_textures(This
);
2190 { /* Set a default viewport */
2194 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2195 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2198 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2201 /* Initialize the current view state */
2202 This
->view_ident
= 1;
2203 This
->contexts
[0]->last_was_rhw
= 0;
2204 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2205 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2207 switch(wined3d_settings
.offscreen_rendering_mode
) {
2210 This
->offscreenBuffer
= GL_BACK
;
2213 case ORM_BACKBUFFER
:
2215 if(This
->activeContext
->aux_buffers
> 0) {
2216 TRACE("Using auxilliary buffer for offscreen rendering\n");
2217 This
->offscreenBuffer
= GL_AUX0
;
2219 TRACE("Using back buffer for offscreen rendering\n");
2220 This
->offscreenBuffer
= GL_BACK
;
2225 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2228 /* Clear the screen */
2229 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2230 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2233 This
->d3d_initialized
= TRUE
;
2235 if(wined3d_settings
.logo
) {
2236 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2238 This
->highest_dirty_ps_const
= 0;
2239 This
->highest_dirty_vs_const
= 0;
2243 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2244 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2245 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2246 This
->NumberOfSwapChains
= 0;
2247 if(This
->palettes
) {
2248 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2249 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2251 This
->NumberOfPalettes
= 0;
2253 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2255 if(This
->stateBlock
) {
2256 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2257 This
->stateBlock
= NULL
;
2259 if (This
->blit_priv
) {
2260 This
->blitter
->free_private(iface
);
2262 if (This
->fragment_priv
) {
2263 This
->frag_pipe
->free_private(iface
);
2265 if (This
->shader_priv
) {
2266 This
->shader_backend
->shader_free_private(iface
);
2271 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2272 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2273 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2276 /* Setup the implicit swapchain */
2277 TRACE("Creating implicit swapchain\n");
2278 hr
=D3DCB_CreateAdditionalSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2279 if (FAILED(hr
) || !swapchain
) {
2280 WARN("Failed to create implicit swapchain\n");
2284 This
->NumberOfSwapChains
= 1;
2285 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2286 if(!This
->swapchains
) {
2287 ERR("Out of memory!\n");
2290 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2294 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2298 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2299 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2302 TRACE("(%p)\n", This
);
2304 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2306 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2307 * it was created. Thus make sure a context is active for the glDelete* calls
2309 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2311 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2313 TRACE("Deleting high order patches\n");
2314 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2315 struct list
*e1
, *e2
;
2316 struct WineD3DRectPatch
*patch
;
2317 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2318 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2319 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2323 /* Delete the palette conversion shader if it is around */
2324 if(This
->paletteConversionShader
) {
2326 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2328 This
->paletteConversionShader
= 0;
2331 /* Delete the pbuffer context if there is any */
2332 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2334 /* Delete the mouse cursor texture */
2335 if(This
->cursorTexture
) {
2337 glDeleteTextures(1, &This
->cursorTexture
);
2339 This
->cursorTexture
= 0;
2342 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2343 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2345 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2346 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2349 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2350 * private data, it might contain opengl pointers
2352 if(This
->depth_blt_texture
) {
2353 glDeleteTextures(1, &This
->depth_blt_texture
);
2354 This
->depth_blt_texture
= 0;
2356 if (This
->depth_blt_rb
) {
2357 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2358 This
->depth_blt_rb
= 0;
2359 This
->depth_blt_rb_w
= 0;
2360 This
->depth_blt_rb_h
= 0;
2363 /* Release the update stateblock */
2364 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2365 if(This
->updateStateBlock
!= This
->stateBlock
)
2366 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2368 This
->updateStateBlock
= NULL
;
2370 { /* because were not doing proper internal refcounts releasing the primary state block
2371 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2372 to set this->stateBlock = NULL; first */
2373 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2374 This
->stateBlock
= NULL
;
2376 /* Release the stateblock */
2377 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2378 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2382 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2383 This
->blitter
->free_private(iface
);
2384 This
->frag_pipe
->free_private(iface
);
2385 This
->shader_backend
->shader_free_private(iface
);
2387 /* Release the buffers (with sanity checks)*/
2388 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2389 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2390 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2391 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2393 This
->stencilBufferTarget
= NULL
;
2395 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2396 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2397 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2399 TRACE("Setting rendertarget to NULL\n");
2400 This
->render_targets
[0] = NULL
;
2402 if (This
->auto_depth_stencil_buffer
) {
2403 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2404 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2406 This
->auto_depth_stencil_buffer
= NULL
;
2409 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2410 TRACE("Releasing the implicit swapchain %d\n", i
);
2411 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2412 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2416 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2417 This
->swapchains
= NULL
;
2418 This
->NumberOfSwapChains
= 0;
2420 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2421 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2422 This
->palettes
= NULL
;
2423 This
->NumberOfPalettes
= 0;
2425 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2426 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2427 This
->render_targets
= NULL
;
2428 This
->draw_buffers
= NULL
;
2430 This
->d3d_initialized
= FALSE
;
2434 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2435 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2438 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2439 TRACE("Releasing the implicit swapchain %d\n", i
);
2440 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2441 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2445 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2446 This
->swapchains
= NULL
;
2447 This
->NumberOfSwapChains
= 0;
2451 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2452 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2453 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2455 * There is no way to deactivate thread safety once it is enabled.
2457 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2458 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2460 /*For now just store the flag(needed in case of ddraw) */
2461 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2466 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2468 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2470 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2473 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2475 /* Resize the screen even without a window:
2476 * The app could have unset it with SetCooperativeLevel, but not called
2477 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2478 * but we don't have any hwnd
2481 memset(&devmode
, 0, sizeof(devmode
));
2482 devmode
.dmSize
= sizeof(devmode
);
2483 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2484 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2485 devmode
.dmPelsWidth
= pMode
->Width
;
2486 devmode
.dmPelsHeight
= pMode
->Height
;
2488 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2489 if (pMode
->RefreshRate
!= 0) {
2490 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2493 /* Only change the mode if necessary */
2494 if( (This
->ddraw_width
== pMode
->Width
) &&
2495 (This
->ddraw_height
== pMode
->Height
) &&
2496 (This
->ddraw_format
== pMode
->Format
) &&
2497 (pMode
->RefreshRate
== 0) ) {
2501 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2502 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2503 if(devmode
.dmDisplayFrequency
!= 0) {
2504 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2505 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2506 devmode
.dmDisplayFrequency
= 0;
2507 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2509 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2510 return WINED3DERR_NOTAVAILABLE
;
2514 /* Store the new values */
2515 This
->ddraw_width
= pMode
->Width
;
2516 This
->ddraw_height
= pMode
->Height
;
2517 This
->ddraw_format
= pMode
->Format
;
2519 /* And finally clip mouse to our screen */
2520 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2521 ClipCursor(&clip_rc
);
2526 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2527 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2528 *ppD3D
= This
->wineD3D
;
2529 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2530 IWineD3D_AddRef(*ppD3D
);
2534 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2535 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2537 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2538 (This
->adapter
->TextureRam
/(1024*1024)),
2539 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2540 /* return simulated texture memory left */
2541 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2549 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2550 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2552 /* Update the current state block */
2553 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2555 if(This
->updateStateBlock
->fvf
== fvf
) {
2556 TRACE("Application is setting the old fvf over, nothing to do\n");
2560 This
->updateStateBlock
->fvf
= fvf
;
2561 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2562 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2567 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2568 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2569 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2570 *pfvf
= This
->stateBlock
->fvf
;
2575 * Get / Set Stream Source
2577 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2579 IWineD3DVertexBuffer
*oldSrc
;
2581 if (StreamNumber
>= MAX_STREAMS
) {
2582 WARN("Stream out of range %d\n", StreamNumber
);
2583 return WINED3DERR_INVALIDCALL
;
2584 } else if(OffsetInBytes
& 0x3) {
2585 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2586 return WINED3DERR_INVALIDCALL
;
2589 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2590 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2592 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2594 if(oldSrc
== pStreamData
&&
2595 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2596 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2597 TRACE("Application is setting the old values over, nothing to do\n");
2601 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2603 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2604 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2607 /* Handle recording of state blocks */
2608 if (This
->isRecordingState
) {
2609 TRACE("Recording... not performing anything\n");
2610 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2611 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2615 /* Need to do a getParent and pass the references up */
2616 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2617 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2618 so for now, just count internally */
2619 if (pStreamData
!= NULL
) {
2620 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2621 InterlockedIncrement(&vbImpl
->bindCount
);
2622 IWineD3DVertexBuffer_AddRef(pStreamData
);
2624 if (oldSrc
!= NULL
) {
2625 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2626 IWineD3DVertexBuffer_Release(oldSrc
);
2629 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2634 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2635 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2637 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2638 This
->stateBlock
->streamSource
[StreamNumber
],
2639 This
->stateBlock
->streamOffset
[StreamNumber
],
2640 This
->stateBlock
->streamStride
[StreamNumber
]);
2642 if (StreamNumber
>= MAX_STREAMS
) {
2643 WARN("Stream out of range %d\n", StreamNumber
);
2644 return WINED3DERR_INVALIDCALL
;
2646 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2647 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2649 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2652 if (*pStream
!= NULL
) {
2653 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2658 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2659 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2660 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2661 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2663 /* Verify input at least in d3d9 this is invalid*/
2664 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2665 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2666 return WINED3DERR_INVALIDCALL
;
2668 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2669 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2670 return WINED3DERR_INVALIDCALL
;
2673 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2674 return WINED3DERR_INVALIDCALL
;
2677 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2678 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2680 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2681 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2683 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2684 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2685 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2691 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2692 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2694 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2695 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2697 TRACE("(%p) : returning %d\n", This
, *Divider
);
2703 * Get / Set & Multiply Transform
2705 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2706 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2708 /* Most of this routine, comments included copied from ddraw tree initially: */
2709 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2711 /* Handle recording of state blocks */
2712 if (This
->isRecordingState
) {
2713 TRACE("Recording... not performing anything\n");
2714 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2715 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2720 * If the new matrix is the same as the current one,
2721 * we cut off any further processing. this seems to be a reasonable
2722 * optimization because as was noticed, some apps (warcraft3 for example)
2723 * tend towards setting the same matrix repeatedly for some reason.
2725 * From here on we assume that the new matrix is different, wherever it matters.
2727 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2728 TRACE("The app is setting the same matrix over again\n");
2731 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2735 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2736 where ViewMat = Camera space, WorldMat = world space.
2738 In OpenGL, camera and world space is combined into GL_MODELVIEW
2739 matrix. The Projection matrix stay projection matrix.
2742 /* Capture the times we can just ignore the change for now */
2743 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2744 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2745 /* Handled by the state manager */
2748 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2752 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2753 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2754 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2755 *pMatrix
= This
->stateBlock
->transforms
[State
];
2759 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2760 WINED3DMATRIX
*mat
= NULL
;
2763 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2764 * below means it will be recorded in a state block change, but it
2765 * works regardless where it is recorded.
2766 * If this is found to be wrong, change to StateBlock.
2768 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2769 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2771 if (State
< HIGHEST_TRANSFORMSTATE
)
2773 mat
= &This
->updateStateBlock
->transforms
[State
];
2775 FIXME("Unhandled transform state!!\n");
2778 multiply_matrix(&temp
, mat
, pMatrix
);
2780 /* Apply change via set transform - will reapply to eg. lights this way */
2781 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2787 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2788 you can reference any indexes you want as long as that number max are enabled at any
2789 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2790 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2791 but when recording, just build a chain pretty much of commands to be replayed. */
2793 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2795 PLIGHTINFOEL
*object
= NULL
;
2796 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2799 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2800 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2802 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2806 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2807 return WINED3DERR_INVALIDCALL
;
2810 switch(pLight
->Type
) {
2811 case WINED3DLIGHT_POINT
:
2812 case WINED3DLIGHT_SPOT
:
2813 case WINED3DLIGHT_PARALLELPOINT
:
2814 case WINED3DLIGHT_GLSPOT
:
2815 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2818 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2819 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2820 return WINED3DERR_INVALIDCALL
;
2824 case WINED3DLIGHT_DIRECTIONAL
:
2825 /* Ignores attenuation */
2829 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2830 return WINED3DERR_INVALIDCALL
;
2833 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2834 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2835 if(object
->OriginalIndex
== Index
) break;
2840 TRACE("Adding new light\n");
2841 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2843 ERR("Out of memory error when allocating a light\n");
2844 return E_OUTOFMEMORY
;
2846 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2847 object
->glIndex
= -1;
2848 object
->OriginalIndex
= Index
;
2849 object
->changed
= TRUE
;
2852 /* Initialize the object */
2853 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
,
2854 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2855 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2856 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2857 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2858 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2859 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2861 /* Save away the information */
2862 object
->OriginalParms
= *pLight
;
2864 switch (pLight
->Type
) {
2865 case WINED3DLIGHT_POINT
:
2867 object
->lightPosn
[0] = pLight
->Position
.x
;
2868 object
->lightPosn
[1] = pLight
->Position
.y
;
2869 object
->lightPosn
[2] = pLight
->Position
.z
;
2870 object
->lightPosn
[3] = 1.0f
;
2871 object
->cutoff
= 180.0f
;
2875 case WINED3DLIGHT_DIRECTIONAL
:
2877 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2878 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2879 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2880 object
->lightPosn
[3] = 0.0;
2881 object
->exponent
= 0.0f
;
2882 object
->cutoff
= 180.0f
;
2885 case WINED3DLIGHT_SPOT
:
2887 object
->lightPosn
[0] = pLight
->Position
.x
;
2888 object
->lightPosn
[1] = pLight
->Position
.y
;
2889 object
->lightPosn
[2] = pLight
->Position
.z
;
2890 object
->lightPosn
[3] = 1.0;
2893 object
->lightDirn
[0] = pLight
->Direction
.x
;
2894 object
->lightDirn
[1] = pLight
->Direction
.y
;
2895 object
->lightDirn
[2] = pLight
->Direction
.z
;
2896 object
->lightDirn
[3] = 1.0;
2899 * opengl-ish and d3d-ish spot lights use too different models for the
2900 * light "intensity" as a function of the angle towards the main light direction,
2901 * so we only can approximate very roughly.
2902 * however spot lights are rather rarely used in games (if ever used at all).
2903 * furthermore if still used, probably nobody pays attention to such details.
2905 if (pLight
->Falloff
== 0) {
2906 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2907 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2908 * will always be 1.0 for both of them, and we don't have to care for the
2909 * rest of the rather complex calculation
2911 object
->exponent
= 0;
2913 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2914 if (rho
< 0.0001) rho
= 0.0001f
;
2915 object
->exponent
= -0.3/log(cos(rho
/2));
2917 if (object
->exponent
> 128.0) {
2918 object
->exponent
= 128.0;
2920 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2926 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2929 /* Update the live definitions if the light is currently assigned a glIndex */
2930 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2931 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2936 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2937 PLIGHTINFOEL
*lightInfo
= NULL
;
2938 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2939 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2941 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2943 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2944 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2945 if(lightInfo
->OriginalIndex
== Index
) break;
2949 if (lightInfo
== NULL
) {
2950 TRACE("Light information requested but light not defined\n");
2951 return WINED3DERR_INVALIDCALL
;
2954 *pLight
= lightInfo
->OriginalParms
;
2959 * Get / Set Light Enable
2960 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2962 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2963 PLIGHTINFOEL
*lightInfo
= NULL
;
2964 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2965 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2967 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2969 /* Tests show true = 128...not clear why */
2970 Enable
= Enable
? 128: 0;
2972 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2973 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2974 if(lightInfo
->OriginalIndex
== Index
) break;
2977 TRACE("Found light: %p\n", lightInfo
);
2979 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2980 if (lightInfo
== NULL
) {
2982 TRACE("Light enabled requested but light not defined, so defining one!\n");
2983 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2985 /* Search for it again! Should be fairly quick as near head of list */
2986 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2987 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2988 if(lightInfo
->OriginalIndex
== Index
) break;
2991 if (lightInfo
== NULL
) {
2992 FIXME("Adding default lights has failed dismally\n");
2993 return WINED3DERR_INVALIDCALL
;
2997 lightInfo
->enabledChanged
= TRUE
;
2999 if(lightInfo
->glIndex
!= -1) {
3000 if(!This
->isRecordingState
) {
3001 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
3004 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
3005 lightInfo
->glIndex
= -1;
3007 TRACE("Light already disabled, nothing to do\n");
3009 lightInfo
->enabled
= FALSE
;
3011 lightInfo
->enabled
= TRUE
;
3012 if (lightInfo
->glIndex
!= -1) {
3014 TRACE("Nothing to do as light was enabled\n");
3017 /* Find a free gl light */
3018 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
3019 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
3020 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
3021 lightInfo
->glIndex
= i
;
3025 if(lightInfo
->glIndex
== -1) {
3026 /* Our tests show that Windows returns D3D_OK in this situation, even with
3027 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3028 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3029 * as well for those lights.
3031 * TODO: Test how this affects rendering
3033 FIXME("Too many concurrently active lights\n");
3037 /* i == lightInfo->glIndex */
3038 if(!This
->isRecordingState
) {
3039 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
3047 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
3049 PLIGHTINFOEL
*lightInfo
= NULL
;
3050 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3052 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3053 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3055 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3056 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3057 if(lightInfo
->OriginalIndex
== Index
) break;
3061 if (lightInfo
== NULL
) {
3062 TRACE("Light enabled state requested but light not defined\n");
3063 return WINED3DERR_INVALIDCALL
;
3065 /* true is 128 according to SetLightEnable */
3066 *pEnable
= lightInfo
->enabled
? 128 : 0;
3071 * Get / Set Clip Planes
3073 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3074 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3075 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3077 /* Validate Index */
3078 if (Index
>= GL_LIMITS(clipplanes
)) {
3079 TRACE("Application has requested clipplane this device doesn't support\n");
3080 return WINED3DERR_INVALIDCALL
;
3083 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
3085 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3086 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3087 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3088 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3089 TRACE("Application is setting old values over, nothing to do\n");
3093 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3094 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3095 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3096 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3098 /* Handle recording of state blocks */
3099 if (This
->isRecordingState
) {
3100 TRACE("Recording... not performing anything\n");
3104 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3109 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3110 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3111 TRACE("(%p) : for idx %d\n", This
, Index
);
3113 /* Validate Index */
3114 if (Index
>= GL_LIMITS(clipplanes
)) {
3115 TRACE("Application has requested clipplane this device doesn't support\n");
3116 return WINED3DERR_INVALIDCALL
;
3119 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3120 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3121 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3122 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3127 * Get / Set Clip Plane Status
3128 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3130 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3131 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3132 FIXME("(%p) : stub\n", This
);
3133 if (NULL
== pClipStatus
) {
3134 return WINED3DERR_INVALIDCALL
;
3136 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3137 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3141 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3142 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3143 FIXME("(%p) : stub\n", This
);
3144 if (NULL
== pClipStatus
) {
3145 return WINED3DERR_INVALIDCALL
;
3147 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3148 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3153 * Get / Set Material
3155 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3156 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3158 This
->updateStateBlock
->changed
.material
= TRUE
;
3159 This
->updateStateBlock
->material
= *pMaterial
;
3161 /* Handle recording of state blocks */
3162 if (This
->isRecordingState
) {
3163 TRACE("Recording... not performing anything\n");
3167 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3171 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3172 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3173 *pMaterial
= This
->updateStateBlock
->material
;
3174 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3175 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3176 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3177 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3178 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3179 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3180 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3181 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3182 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3190 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3191 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3192 IWineD3DIndexBuffer
*oldIdxs
;
3194 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3195 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3197 This
->updateStateBlock
->changed
.indices
= TRUE
;
3198 This
->updateStateBlock
->pIndexData
= pIndexData
;
3200 /* Handle recording of state blocks */
3201 if (This
->isRecordingState
) {
3202 TRACE("Recording... not performing anything\n");
3203 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3204 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3208 if(oldIdxs
!= pIndexData
) {
3209 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3210 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3211 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3216 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3217 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3219 *ppIndexData
= This
->stateBlock
->pIndexData
;
3221 /* up ref count on ppindexdata */
3223 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3224 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3226 TRACE("(%p) No index data set\n", This
);
3228 TRACE("Returning %p\n", *ppIndexData
);
3233 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3234 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3235 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3236 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3238 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3239 TRACE("Application is setting the old value over, nothing to do\n");
3243 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3245 if (This
->isRecordingState
) {
3246 TRACE("Recording... not performing anything\n");
3249 /* The base vertex index affects the stream sources */
3250 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3254 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3255 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3256 TRACE("(%p) : base_index %p\n", This
, base_index
);
3258 *base_index
= This
->stateBlock
->baseVertexIndex
;
3260 TRACE("Returning %u\n", *base_index
);
3266 * Get / Set Viewports
3268 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3269 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3271 TRACE("(%p)\n", This
);
3272 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3273 This
->updateStateBlock
->viewport
= *pViewport
;
3275 /* Handle recording of state blocks */
3276 if (This
->isRecordingState
) {
3277 TRACE("Recording... not performing anything\n");
3281 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3282 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3284 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3289 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3290 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3291 TRACE("(%p)\n", This
);
3292 *pViewport
= This
->stateBlock
->viewport
;
3297 * Get / Set Render States
3298 * TODO: Verify against dx9 definitions
3300 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3302 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3303 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3305 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3307 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3308 This
->updateStateBlock
->renderState
[State
] = Value
;
3310 /* Handle recording of state blocks */
3311 if (This
->isRecordingState
) {
3312 TRACE("Recording... not performing anything\n");
3316 /* Compared here and not before the assignment to allow proper stateblock recording */
3317 if(Value
== oldValue
) {
3318 TRACE("Application is setting the old value over, nothing to do\n");
3320 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3326 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3327 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3328 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3329 *pValue
= This
->stateBlock
->renderState
[State
];
3334 * Get / Set Sampler States
3335 * TODO: Verify against dx9 definitions
3338 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3339 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3342 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3343 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3345 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3346 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3349 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3350 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3351 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3354 * SetSampler is designed to allow for more than the standard up to 8 textures
3355 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3356 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3358 * http://developer.nvidia.com/object/General_FAQ.html#t6
3360 * There are two new settings for GForce
3362 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3363 * and the texture one:
3364 * GL_MAX_TEXTURE_COORDS_ARB.
3365 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3368 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3369 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3370 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3372 /* Handle recording of state blocks */
3373 if (This
->isRecordingState
) {
3374 TRACE("Recording... not performing anything\n");
3378 if(oldValue
== Value
) {
3379 TRACE("Application is setting the old value over, nothing to do\n");
3383 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3388 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3389 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3391 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3392 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3394 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3395 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3398 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3399 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3400 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3402 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3403 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3408 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3409 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3411 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3412 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3413 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3416 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3418 if(This
->isRecordingState
) {
3419 TRACE("Recording... not performing anything\n");
3423 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3428 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3429 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3431 *pRect
= This
->updateStateBlock
->scissorRect
;
3432 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3436 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3437 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3438 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3440 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3442 This
->updateStateBlock
->vertexDecl
= pDecl
;
3443 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3445 if (This
->isRecordingState
) {
3446 TRACE("Recording... not performing anything\n");
3448 } else if(pDecl
== oldDecl
) {
3449 /* Checked after the assignment to allow proper stateblock recording */
3450 TRACE("Application is setting the old declaration over, nothing to do\n");
3454 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3458 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3459 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3461 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3463 *ppDecl
= This
->stateBlock
->vertexDecl
;
3464 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3468 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3469 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3470 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3472 This
->updateStateBlock
->vertexShader
= pShader
;
3473 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3475 if (This
->isRecordingState
) {
3476 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3477 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3478 TRACE("Recording... not performing anything\n");
3480 } else if(oldShader
== pShader
) {
3481 /* Checked here to allow proper stateblock recording */
3482 TRACE("App is setting the old shader over, nothing to do\n");
3486 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3487 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3488 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3490 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3495 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3496 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3498 if (NULL
== ppShader
) {
3499 return WINED3DERR_INVALIDCALL
;
3501 *ppShader
= This
->stateBlock
->vertexShader
;
3502 if( NULL
!= *ppShader
)
3503 IWineD3DVertexShader_AddRef(*ppShader
);
3505 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3509 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3510 IWineD3DDevice
*iface
,
3512 CONST BOOL
*srcData
,
3515 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3516 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3518 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3519 iface
, srcData
, start
, count
);
3521 if (srcData
== NULL
|| cnt
< 0)
3522 return WINED3DERR_INVALIDCALL
;
3524 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3525 for (i
= 0; i
< cnt
; i
++)
3526 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3528 for (i
= start
; i
< cnt
+ start
; ++i
) {
3529 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3532 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3537 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3538 IWineD3DDevice
*iface
,
3543 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3544 int cnt
= min(count
, MAX_CONST_B
- start
);
3546 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3547 iface
, dstData
, start
, count
);
3549 if (dstData
== NULL
|| cnt
< 0)
3550 return WINED3DERR_INVALIDCALL
;
3552 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3556 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3557 IWineD3DDevice
*iface
,
3562 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3563 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3565 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3566 iface
, srcData
, start
, count
);
3568 if (srcData
== NULL
|| cnt
< 0)
3569 return WINED3DERR_INVALIDCALL
;
3571 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3572 for (i
= 0; i
< cnt
; i
++)
3573 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3574 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3576 for (i
= start
; i
< cnt
+ start
; ++i
) {
3577 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3580 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3585 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3586 IWineD3DDevice
*iface
,
3591 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3592 int cnt
= min(count
, MAX_CONST_I
- start
);
3594 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3595 iface
, dstData
, start
, count
);
3597 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3598 return WINED3DERR_INVALIDCALL
;
3600 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3604 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3605 IWineD3DDevice
*iface
,
3607 CONST
float *srcData
,
3610 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3613 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3614 iface
, srcData
, start
, count
);
3616 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3617 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3618 return WINED3DERR_INVALIDCALL
;
3620 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3622 for (i
= 0; i
< count
; i
++)
3623 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3624 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3627 for (i
= start
; i
< count
+ start
; ++i
) {
3628 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3629 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3630 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3631 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3632 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3634 ptr
->idx
[ptr
->count
++] = i
;
3635 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3639 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3644 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3645 IWineD3DDevice
*iface
,
3647 CONST
float *srcData
,
3650 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3653 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3654 iface
, srcData
, start
, count
);
3656 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3657 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3658 return WINED3DERR_INVALIDCALL
;
3660 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3662 for (i
= 0; i
< count
; i
++)
3663 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3664 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3667 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3668 * context. On a context switch the old context will be fully dirtified
3670 memset(This
->activeContext
->vshader_const_dirty
+ start
, 1,
3671 sizeof(*This
->activeContext
->vshader_const_dirty
) * count
);
3672 This
->highest_dirty_vs_const
= max(This
->highest_dirty_vs_const
, start
+count
+1);
3674 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3679 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3680 IWineD3DDevice
*iface
,
3685 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3686 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3688 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3689 iface
, dstData
, start
, count
);
3691 if (dstData
== NULL
|| cnt
< 0)
3692 return WINED3DERR_INVALIDCALL
;
3694 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3698 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3700 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3701 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3705 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3706 int i
= This
->rev_tex_unit_map
[unit
];
3707 int j
= This
->texUnitMap
[stage
];
3709 This
->texUnitMap
[stage
] = unit
;
3710 if (i
!= -1 && i
!= stage
) {
3711 This
->texUnitMap
[i
] = -1;
3714 This
->rev_tex_unit_map
[unit
] = stage
;
3715 if (j
!= -1 && j
!= unit
) {
3716 This
->rev_tex_unit_map
[j
] = -1;
3720 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3723 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3724 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3725 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3726 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3727 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3728 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3729 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3730 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3731 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3733 if (color_op
== WINED3DTOP_DISABLE
) {
3734 /* Not used, and disable higher stages */
3735 while (i
< MAX_TEXTURES
) {
3736 This
->fixed_function_usage_map
[i
] = FALSE
;
3742 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3743 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3744 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3745 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3746 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3747 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3748 This
->fixed_function_usage_map
[i
] = TRUE
;
3750 This
->fixed_function_usage_map
[i
] = FALSE
;
3753 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3754 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3759 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3762 device_update_fixed_function_usage_map(This
);
3764 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3765 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3766 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3767 if (!This
->fixed_function_usage_map
[i
]) continue;
3769 if (This
->texUnitMap
[i
] != i
) {
3770 device_map_stage(This
, i
, i
);
3771 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3772 markTextureStagesDirty(This
, i
);
3778 /* Now work out the mapping */
3780 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3781 if (!This
->fixed_function_usage_map
[i
]) continue;
3783 if (This
->texUnitMap
[i
] != tex
) {
3784 device_map_stage(This
, i
, tex
);
3785 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3786 markTextureStagesDirty(This
, i
);
3793 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3794 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3797 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3798 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3799 device_map_stage(This
, i
, i
);
3800 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3801 if (i
< MAX_TEXTURES
) {
3802 markTextureStagesDirty(This
, i
);
3808 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3809 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3811 if (current_mapping
== -1) {
3812 /* Not currently used */
3816 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3817 /* Used by a fragment sampler */
3819 if (!pshader_sampler_tokens
) {
3820 /* No pixel shader, check fixed function */
3821 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3824 /* Pixel shader, check the shader's sampler map */
3825 return !pshader_sampler_tokens
[current_mapping
];
3828 /* Used by a vertex sampler */
3829 return !vshader_sampler_tokens
[current_mapping
];
3832 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3833 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3834 DWORD
*pshader_sampler_tokens
= NULL
;
3835 int start
= GL_LIMITS(combined_samplers
) - 1;
3839 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3841 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3842 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3843 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3846 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3847 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3848 if (vshader_sampler_tokens
[i
]) {
3849 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3850 /* Already mapped somewhere */
3854 while (start
>= 0) {
3855 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3856 device_map_stage(This
, vsampler_idx
, start
);
3857 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3869 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3870 BOOL vs
= use_vs(This
);
3871 BOOL ps
= use_ps(This
);
3874 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3875 * that would be really messy and require shader recompilation
3876 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3877 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3880 device_map_psamplers(This
);
3882 device_map_fixed_function_samplers(This
);
3886 device_map_vsamplers(This
, ps
);
3890 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3891 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3892 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3893 This
->updateStateBlock
->pixelShader
= pShader
;
3894 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3896 /* Handle recording of state blocks */
3897 if (This
->isRecordingState
) {
3898 TRACE("Recording... not performing anything\n");
3901 if (This
->isRecordingState
) {
3902 TRACE("Recording... not performing anything\n");
3903 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3904 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3908 if(pShader
== oldShader
) {
3909 TRACE("App is setting the old pixel shader over, nothing to do\n");
3913 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3914 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3916 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3917 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3922 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3923 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3925 if (NULL
== ppShader
) {
3926 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3927 return WINED3DERR_INVALIDCALL
;
3930 *ppShader
= This
->stateBlock
->pixelShader
;
3931 if (NULL
!= *ppShader
) {
3932 IWineD3DPixelShader_AddRef(*ppShader
);
3934 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3938 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3939 IWineD3DDevice
*iface
,
3941 CONST BOOL
*srcData
,
3944 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3945 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3947 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3948 iface
, srcData
, start
, count
);
3950 if (srcData
== NULL
|| cnt
< 0)
3951 return WINED3DERR_INVALIDCALL
;
3953 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3954 for (i
= 0; i
< cnt
; i
++)
3955 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3957 for (i
= start
; i
< cnt
+ start
; ++i
) {
3958 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3961 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3966 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3967 IWineD3DDevice
*iface
,
3972 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3973 int cnt
= min(count
, MAX_CONST_B
- start
);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface
, dstData
, start
, count
);
3978 if (dstData
== NULL
|| cnt
< 0)
3979 return WINED3DERR_INVALIDCALL
;
3981 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3985 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3986 IWineD3DDevice
*iface
,
3991 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3992 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface
, srcData
, start
, count
);
3997 if (srcData
== NULL
|| cnt
< 0)
3998 return WINED3DERR_INVALIDCALL
;
4000 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
4001 for (i
= 0; i
< cnt
; i
++)
4002 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
4003 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4005 for (i
= start
; i
< cnt
+ start
; ++i
) {
4006 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
4009 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4014 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
4015 IWineD3DDevice
*iface
,
4020 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4021 int cnt
= min(count
, MAX_CONST_I
- start
);
4023 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4024 iface
, dstData
, start
, count
);
4026 if (dstData
== NULL
|| cnt
< 0)
4027 return WINED3DERR_INVALIDCALL
;
4029 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
4033 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
4034 IWineD3DDevice
*iface
,
4036 CONST
float *srcData
,
4039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4042 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4043 iface
, srcData
, start
, count
);
4045 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4046 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4047 return WINED3DERR_INVALIDCALL
;
4049 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4051 for (i
= 0; i
< count
; i
++)
4052 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4053 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4056 for (i
= start
; i
< count
+ start
; ++i
) {
4057 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
4058 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
4059 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
4060 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
4061 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
4063 ptr
->idx
[ptr
->count
++] = i
;
4064 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
4068 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4073 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4074 IWineD3DDevice
*iface
,
4076 CONST
float *srcData
,
4079 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4082 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4083 iface
, srcData
, start
, count
);
4085 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4086 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4087 return WINED3DERR_INVALIDCALL
;
4089 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4091 for (i
= 0; i
< count
; i
++)
4092 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4093 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4096 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4097 * context. On a context switch the old context will be fully dirtified
4099 memset(This
->activeContext
->pshader_const_dirty
+ start
, 1,
4100 sizeof(*This
->activeContext
->pshader_const_dirty
) * count
);
4101 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, start
+count
+1);
4103 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4108 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
4109 IWineD3DDevice
*iface
,
4114 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4115 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
4117 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4118 iface
, dstData
, start
, count
);
4120 if (dstData
== NULL
|| cnt
< 0)
4121 return WINED3DERR_INVALIDCALL
;
4123 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4127 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4129 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
4130 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4132 DWORD DestFVF
= dest
->fvf
;
4134 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4138 if (lpStrideData
->u
.s
.normal
.lpData
) {
4139 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4142 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
4143 ERR("Source has no position mask\n");
4144 return WINED3DERR_INVALIDCALL
;
4147 /* We might access VBOs from this code, so hold the lock */
4150 if (dest
->resource
.allocatedMemory
== NULL
) {
4151 /* This may happen if we do direct locking into a vbo. Unlikely,
4152 * but theoretically possible(ddraw processvertices test)
4154 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4155 if(!dest
->resource
.allocatedMemory
) {
4157 ERR("Out of memory\n");
4158 return E_OUTOFMEMORY
;
4162 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4163 checkGLcall("glBindBufferARB");
4164 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4166 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4168 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4169 checkGLcall("glUnmapBufferARB");
4173 /* Get a pointer into the destination vbo(create one if none exists) and
4174 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4176 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
4177 dest
->Flags
|= VBFLAG_CREATEVBO
;
4178 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer
*) dest
);
4182 unsigned char extrabytes
= 0;
4183 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4184 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4185 * this may write 4 extra bytes beyond the area that should be written
4187 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4188 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4189 if(!dest_conv_addr
) {
4190 ERR("Out of memory\n");
4191 /* Continue without storing converted vertices */
4193 dest_conv
= dest_conv_addr
;
4197 * a) WINED3DRS_CLIPPING is enabled
4198 * b) WINED3DVOP_CLIP is passed
4200 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4201 static BOOL warned
= FALSE
;
4203 * The clipping code is not quite correct. Some things need
4204 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4205 * so disable clipping for now.
4206 * (The graphics in Half-Life are broken, and my processvertices
4207 * test crashes with IDirect3DDevice3)
4213 FIXME("Clipping is broken and disabled for now\n");
4215 } else doClip
= FALSE
;
4216 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4218 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4221 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4222 WINED3DTS_PROJECTION
,
4224 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4225 WINED3DTS_WORLDMATRIX(0),
4228 TRACE("View mat:\n");
4229 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
);
4230 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
);
4231 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
);
4232 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
);
4234 TRACE("Proj mat:\n");
4235 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
);
4236 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
);
4237 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
);
4238 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
);
4240 TRACE("World mat:\n");
4241 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
);
4242 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
);
4243 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
);
4244 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
);
4246 /* Get the viewport */
4247 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4248 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4249 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4251 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4252 multiply_matrix(&mat
,&proj_mat
,&mat
);
4254 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4256 for (i
= 0; i
< dwCount
; i
+= 1) {
4257 unsigned int tex_index
;
4259 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4260 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4261 /* The position first */
4263 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4265 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4267 /* Multiplication with world, view and projection matrix */
4268 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
);
4269 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
);
4270 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
);
4271 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
);
4273 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4275 /* WARNING: The following things are taken from d3d7 and were not yet checked
4276 * against d3d8 or d3d9!
4279 /* Clipping conditions: From msdn
4281 * A vertex is clipped if it does not match the following requirements
4285 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4287 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4288 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4293 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4294 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4297 /* "Normal" viewport transformation (not clipped)
4298 * 1) The values are divided by rhw
4299 * 2) The y axis is negative, so multiply it with -1
4300 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4301 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4302 * 4) Multiply x with Width/2 and add Width/2
4303 * 5) The same for the height
4304 * 6) Add the viewpoint X and Y to the 2D coordinates and
4305 * The minimum Z value to z
4306 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4308 * Well, basically it's simply a linear transformation into viewport
4320 z
*= vp
.MaxZ
- vp
.MinZ
;
4322 x
+= vp
.Width
/ 2 + vp
.X
;
4323 y
+= vp
.Height
/ 2 + vp
.Y
;
4328 /* That vertex got clipped
4329 * Contrary to OpenGL it is not dropped completely, it just
4330 * undergoes a different calculation.
4332 TRACE("Vertex got clipped\n");
4339 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4340 * outside of the main vertex buffer memory. That needs some more
4345 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4348 ( (float *) dest_ptr
)[0] = x
;
4349 ( (float *) dest_ptr
)[1] = y
;
4350 ( (float *) dest_ptr
)[2] = z
;
4351 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4353 dest_ptr
+= 3 * sizeof(float);
4355 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4356 dest_ptr
+= sizeof(float);
4361 ( (float *) dest_conv
)[0] = x
* w
;
4362 ( (float *) dest_conv
)[1] = y
* w
;
4363 ( (float *) dest_conv
)[2] = z
* w
;
4364 ( (float *) dest_conv
)[3] = w
;
4366 dest_conv
+= 3 * sizeof(float);
4368 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4369 dest_conv
+= sizeof(float);
4373 if (DestFVF
& WINED3DFVF_PSIZE
) {
4374 dest_ptr
+= sizeof(DWORD
);
4375 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4377 if (DestFVF
& WINED3DFVF_NORMAL
) {
4379 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4380 /* AFAIK this should go into the lighting information */
4381 FIXME("Didn't expect the destination to have a normal\n");
4382 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4384 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4388 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4390 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4392 static BOOL warned
= FALSE
;
4395 ERR("No diffuse color in source, but destination has one\n");
4399 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4400 dest_ptr
+= sizeof(DWORD
);
4403 *( (DWORD
*) dest_conv
) = 0xffffffff;
4404 dest_conv
+= sizeof(DWORD
);
4408 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4410 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4411 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4412 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4413 dest_conv
+= sizeof(DWORD
);
4418 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4419 /* What's the color value in the feedback buffer? */
4421 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4423 static BOOL warned
= FALSE
;
4426 ERR("No specular color in source, but destination has one\n");
4430 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4431 dest_ptr
+= sizeof(DWORD
);
4434 *( (DWORD
*) dest_conv
) = 0xFF000000;
4435 dest_conv
+= sizeof(DWORD
);
4439 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4441 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4442 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4443 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4444 dest_conv
+= sizeof(DWORD
);
4449 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4451 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4452 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4454 ERR("No source texture, but destination requests one\n");
4455 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4456 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4459 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4461 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4468 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4469 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4470 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4471 dwCount
* get_flexible_vertex_size(DestFVF
),
4473 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4474 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4481 #undef copy_and_next
4483 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4484 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4485 WineDirect3DVertexStridedData strided
;
4486 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4487 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4490 ERR("Output vertex declaration not implemented yet\n");
4493 /* Need any context to write to the vbo. */
4494 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4496 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4497 * control the streamIsUP flag, thus restore it afterwards.
4499 This
->stateBlock
->streamIsUP
= FALSE
;
4500 memset(&strided
, 0, sizeof(strided
));
4501 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4502 This
->stateBlock
->streamIsUP
= streamWasUP
;
4504 if(vbo
|| SrcStartIndex
) {
4506 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4507 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4509 * Also get the start index in, but only loop over all elements if there's something to add at all.
4511 #define FIXSRC(type) \
4512 if(strided.u.s.type.VBO) { \
4513 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4514 strided.u.s.type.VBO = 0; \
4515 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4517 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4521 if(strided.u.s.type.lpData) { \
4522 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4525 FIXSRC(blendWeights
);
4526 FIXSRC(blendMatrixIndices
);
4531 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4532 FIXSRC(texCoords
[i
]);
4545 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4549 * Get / Set Texture Stage States
4550 * TODO: Verify against dx9 definitions
4552 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4553 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4554 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4556 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4558 if (Stage
>= MAX_TEXTURES
) {
4559 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4563 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4564 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4566 if (This
->isRecordingState
) {
4567 TRACE("Recording... not performing anything\n");
4571 /* Checked after the assignments to allow proper stateblock recording */
4572 if(oldValue
== Value
) {
4573 TRACE("App is setting the old value over, nothing to do\n");
4577 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4578 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4579 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4580 * Changes in other states are important on disabled stages too
4585 if(Type
== WINED3DTSS_COLOROP
) {
4588 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4589 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4590 * they have to be disabled
4592 * The current stage is dirtified below.
4594 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4595 TRACE("Additionally dirtifying stage %d\n", i
);
4596 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4598 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4599 TRACE("New lowest disabled: %d\n", Stage
);
4600 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4601 /* Previously disabled stage enabled. Stages above it may need enabling
4602 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4603 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4605 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4608 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4609 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4612 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4613 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4615 This
->stateBlock
->lowest_disabled_stage
= i
;
4616 TRACE("New lowest disabled: %d\n", i
);
4620 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4625 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4626 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4627 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4628 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4635 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4636 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4637 IWineD3DBaseTexture
*oldTexture
;
4639 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4641 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4642 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4645 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4646 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4647 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4650 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4652 if(pTexture
!= NULL
) {
4653 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4655 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4656 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4657 return WINED3DERR_INVALIDCALL
;
4659 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4662 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4663 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4665 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4666 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4667 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4669 /* Handle recording of state blocks */
4670 if (This
->isRecordingState
) {
4671 TRACE("Recording... not performing anything\n");
4675 if(oldTexture
== pTexture
) {
4676 TRACE("App is setting the same texture again, nothing to do\n");
4680 /** NOTE: MSDN says that setTexture increases the reference count,
4681 * and that the application must set the texture back to null (or have a leaky application),
4682 * This means we should pass the refcount up to the parent
4683 *******************************/
4684 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4685 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4686 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4688 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4689 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4690 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4691 * so the COLOROP and ALPHAOP have to be dirtified.
4693 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4694 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4696 if(bindCount
== 1) {
4697 new->baseTexture
.sampler
= Stage
;
4699 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4703 if (NULL
!= oldTexture
) {
4704 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4705 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4707 IWineD3DBaseTexture_Release(oldTexture
);
4708 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4709 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4710 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4713 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4715 /* Have to do a search for the other sampler(s) where the texture is bound to
4716 * Shouldn't happen as long as apps bind a texture only to one stage
4718 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4719 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4720 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4721 old
->baseTexture
.sampler
= i
;
4728 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4733 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4734 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4736 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4738 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4739 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4742 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4743 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4744 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4747 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4749 IWineD3DBaseTexture_AddRef(*ppTexture
);
4751 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4759 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4760 IWineD3DSurface
**ppBackBuffer
) {
4761 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4762 IWineD3DSwapChain
*swapChain
;
4765 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4767 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4768 if (hr
== WINED3D_OK
) {
4769 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4770 IWineD3DSwapChain_Release(swapChain
);
4772 *ppBackBuffer
= NULL
;
4777 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4778 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4779 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4780 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4783 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4784 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4785 IWineD3DSwapChain
*swapChain
;
4788 if(iSwapChain
> 0) {
4789 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4790 if (hr
== WINED3D_OK
) {
4791 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4792 IWineD3DSwapChain_Release(swapChain
);
4794 FIXME("(%p) Error getting display mode\n", This
);
4797 /* Don't read the real display mode,
4798 but return the stored mode instead. X11 can't change the color
4799 depth, and some apps are pretty angry if they SetDisplayMode from
4800 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4802 Also don't relay to the swapchain because with ddraw it's possible
4803 that there isn't a swapchain at all */
4804 pMode
->Width
= This
->ddraw_width
;
4805 pMode
->Height
= This
->ddraw_height
;
4806 pMode
->Format
= This
->ddraw_format
;
4807 pMode
->RefreshRate
= 0;
4815 * Stateblock related functions
4818 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4819 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4820 IWineD3DStateBlockImpl
*object
;
4821 HRESULT temp_result
;
4824 TRACE("(%p)\n", This
);
4826 if (This
->isRecordingState
) {
4827 return WINED3DERR_INVALIDCALL
;
4830 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4831 if (NULL
== object
) {
4832 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4833 return E_OUTOFMEMORY
;
4835 TRACE("(%p) created object %p\n", This
, object
);
4836 object
->wineD3DDevice
= This
;
4837 /** FIXME: object->parent = parent; **/
4838 object
->parent
= NULL
;
4839 object
->blockType
= WINED3DSBT_RECORDED
;
4841 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4843 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4844 list_init(&object
->lightMap
[i
]);
4847 temp_result
= allocate_shader_constants(object
);
4848 if (WINED3D_OK
!= temp_result
)
4851 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4852 This
->updateStateBlock
= object
;
4853 This
->isRecordingState
= TRUE
;
4855 TRACE("(%p) recording stateblock %p\n",This
, object
);
4859 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4860 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4862 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4864 if (!This
->isRecordingState
) {
4865 FIXME("(%p) not recording! returning error\n", This
);
4866 *ppStateBlock
= NULL
;
4867 return WINED3DERR_INVALIDCALL
;
4870 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4871 if(object
->changed
.renderState
[i
]) {
4872 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4873 object
->num_contained_render_states
++;
4876 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4877 if(object
->changed
.transform
[i
]) {
4878 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4879 object
->num_contained_transform_states
++;
4882 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4883 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4884 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4885 object
->num_contained_vs_consts_f
++;
4888 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4889 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4890 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4891 object
->num_contained_vs_consts_i
++;
4894 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4895 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4896 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4897 object
->num_contained_vs_consts_b
++;
4900 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4901 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4902 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4903 object
->num_contained_ps_consts_i
++;
4906 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4907 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4908 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4909 object
->num_contained_ps_consts_b
++;
4912 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4913 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4914 if(object
->changed
.textureState
[i
][j
]) {
4915 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4916 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4917 object
->num_contained_tss_states
++;
4921 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4922 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4923 if(object
->changed
.samplerState
[i
][j
]) {
4924 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4925 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4926 object
->num_contained_sampler_states
++;
4931 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4932 This
->isRecordingState
= FALSE
;
4933 This
->updateStateBlock
= This
->stateBlock
;
4934 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4935 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4936 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4941 * Scene related functions
4943 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4944 /* At the moment we have no need for any functionality at the beginning
4946 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4947 TRACE("(%p)\n", This
);
4950 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4951 return WINED3DERR_INVALIDCALL
;
4953 This
->inScene
= TRUE
;
4957 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4958 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4959 TRACE("(%p)\n", This
);
4961 if(!This
->inScene
) {
4962 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4963 return WINED3DERR_INVALIDCALL
;
4966 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4967 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4969 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4973 This
->inScene
= FALSE
;
4977 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4978 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4979 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4980 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4981 IWineD3DSwapChain
*swapChain
= NULL
;
4983 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4985 TRACE("(%p) Presenting the frame\n", This
);
4987 for(i
= 0 ; i
< swapchains
; i
++) {
4989 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4990 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4991 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4992 IWineD3DSwapChain_Release(swapChain
);
4998 /* Not called from the VTable (internal subroutine) */
4999 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
5000 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
5001 float Z
, DWORD Stencil
) {
5002 GLbitfield glMask
= 0;
5004 WINED3DRECT curRect
;
5006 WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
5007 UINT drawable_width
, drawable_height
;
5008 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
5009 IWineD3DSwapChainImpl
*swapchain
= NULL
;
5011 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5012 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5013 * for the cleared parts, and the untouched parts.
5015 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5016 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5017 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5018 * checking all this if the dest surface is in the drawable anyway.
5020 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
5022 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
5023 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
5024 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5027 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5028 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5029 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
5030 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
5031 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5034 if(Count
> 0 && pRects
&& (
5035 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5036 pRects
[0].x2
< target
->currentDesc
.Width
||
5037 pRects
[0].y2
< target
->currentDesc
.Height
)) {
5038 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5045 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
5047 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
5050 /* Only set the values up once, as they are not changing */
5051 if (Flags
& WINED3DCLEAR_STENCIL
) {
5052 glClearStencil(Stencil
);
5053 checkGLcall("glClearStencil");
5054 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
5055 glStencilMask(0xFFFFFFFF);
5058 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5059 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5060 glDepthMask(GL_TRUE
);
5062 checkGLcall("glClearDepth");
5063 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
5064 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
5066 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
5067 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
5068 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5070 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5071 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5072 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
5073 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
5074 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5076 else if (Count
> 0 && pRects
&& (
5077 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5078 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
5079 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
5080 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5084 if (Flags
& WINED3DCLEAR_TARGET
) {
5085 TRACE("Clearing screen with glClear to color %x\n", Color
);
5086 glClearColor(D3DCOLOR_R(Color
),
5090 checkGLcall("glClearColor");
5092 /* Clear ALL colors! */
5093 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5094 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
5097 vp_rect
.left
= vp
->X
;
5098 vp_rect
.top
= vp
->Y
;
5099 vp_rect
.right
= vp
->X
+ vp
->Width
;
5100 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5101 if (!(Count
> 0 && pRects
)) {
5102 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5103 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5105 if(This
->render_offscreen
) {
5106 glScissor(vp_rect
.left
, vp_rect
.top
,
5107 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5109 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5110 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5112 checkGLcall("glScissor");
5114 checkGLcall("glClear");
5116 /* Now process each rect in turn */
5117 for (i
= 0; i
< Count
; i
++) {
5118 /* Note gl uses lower left, width/height */
5119 IntersectRect((RECT
*) &curRect
, &vp_rect
, (RECT
*) &pRects
[i
]);
5120 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5121 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5123 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5124 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5125 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5126 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5128 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5129 * The rectangle is not cleared, no error is returned, but further rectanlges are
5130 * still cleared if they are valid
5132 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5133 TRACE("Rectangle with negative dimensions, ignoring\n");
5137 if(This
->render_offscreen
) {
5138 glScissor(curRect
.x1
, curRect
.y1
,
5139 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5141 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5142 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5144 checkGLcall("glScissor");
5147 checkGLcall("glClear");
5151 /* Restore the old values (why..?) */
5152 if (Flags
& WINED3DCLEAR_STENCIL
) {
5153 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5155 if (Flags
& WINED3DCLEAR_TARGET
) {
5156 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5157 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5158 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5159 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5160 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5162 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5163 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5165 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5167 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5168 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5169 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5170 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5175 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5177 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
5180 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5186 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5187 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5188 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5189 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5191 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5192 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5194 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5195 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5196 /* TODO: What about depth stencil buffers without stencil bits? */
5197 return WINED3DERR_INVALIDCALL
;
5200 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5206 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
5207 UINT PrimitiveCount
) {
5209 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5211 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
5212 debug_d3dprimitivetype(PrimitiveType
),
5213 StartVertex
, PrimitiveCount
);
5215 if(!This
->stateBlock
->vertexDecl
) {
5216 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5217 return WINED3DERR_INVALIDCALL
;
5220 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5221 if(This
->stateBlock
->streamIsUP
) {
5222 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5223 This
->stateBlock
->streamIsUP
= FALSE
;
5226 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5227 This
->stateBlock
->loadBaseVertexIndex
= 0;
5228 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5230 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5231 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
5232 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5236 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5237 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5238 WINED3DPRIMITIVETYPE PrimitiveType
,
5239 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
5241 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5243 IWineD3DIndexBuffer
*pIB
;
5244 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
5247 pIB
= This
->stateBlock
->pIndexData
;
5249 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5250 * without an index buffer set. (The first time at least...)
5251 * D3D8 simply dies, but I doubt it can do much harm to return
5252 * D3DERR_INVALIDCALL there as well. */
5253 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5254 return WINED3DERR_INVALIDCALL
;
5257 if(!This
->stateBlock
->vertexDecl
) {
5258 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5259 return WINED3DERR_INVALIDCALL
;
5262 if(This
->stateBlock
->streamIsUP
) {
5263 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5264 This
->stateBlock
->streamIsUP
= FALSE
;
5266 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5268 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5269 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5270 minIndex
, NumVertices
, startIndex
, primCount
);
5272 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5273 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5279 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5280 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5281 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5284 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5285 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5290 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5291 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5292 UINT VertexStreamZeroStride
) {
5293 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5294 IWineD3DVertexBuffer
*vb
;
5296 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5297 debug_d3dprimitivetype(PrimitiveType
),
5298 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5300 if(!This
->stateBlock
->vertexDecl
) {
5301 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5302 return WINED3DERR_INVALIDCALL
;
5305 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5306 vb
= This
->stateBlock
->streamSource
[0];
5307 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5308 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5309 This
->stateBlock
->streamOffset
[0] = 0;
5310 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5311 This
->stateBlock
->streamIsUP
= TRUE
;
5312 This
->stateBlock
->loadBaseVertexIndex
= 0;
5314 /* TODO: Only mark dirty if drawing from a different UP address */
5315 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5317 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5318 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5320 /* MSDN specifies stream zero settings must be set to NULL */
5321 This
->stateBlock
->streamStride
[0] = 0;
5322 This
->stateBlock
->streamSource
[0] = NULL
;
5324 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5325 * the new stream sources or use UP drawing again
5330 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5331 UINT MinVertexIndex
, UINT NumVertices
,
5332 UINT PrimitiveCount
, CONST
void* pIndexData
,
5333 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5334 UINT VertexStreamZeroStride
) {
5336 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5337 IWineD3DVertexBuffer
*vb
;
5338 IWineD3DIndexBuffer
*ib
;
5340 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5341 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5342 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5343 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5345 if(!This
->stateBlock
->vertexDecl
) {
5346 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5347 return WINED3DERR_INVALIDCALL
;
5350 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5356 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5357 vb
= This
->stateBlock
->streamSource
[0];
5358 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5359 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5360 This
->stateBlock
->streamIsUP
= TRUE
;
5361 This
->stateBlock
->streamOffset
[0] = 0;
5362 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5364 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5365 This
->stateBlock
->baseVertexIndex
= 0;
5366 This
->stateBlock
->loadBaseVertexIndex
= 0;
5367 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5368 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5369 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5371 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5373 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5374 This
->stateBlock
->streamSource
[0] = NULL
;
5375 This
->stateBlock
->streamStride
[0] = 0;
5376 ib
= This
->stateBlock
->pIndexData
;
5378 IWineD3DIndexBuffer_Release(ib
);
5379 This
->stateBlock
->pIndexData
= NULL
;
5381 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5382 * SetStreamSource to specify a vertex buffer
5388 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5389 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5391 /* Mark the state dirty until we have nicer tracking
5392 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5395 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5396 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5397 This
->stateBlock
->baseVertexIndex
= 0;
5398 This
->up_strided
= DrawPrimStrideData
;
5399 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5400 This
->up_strided
= NULL
;
5404 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5405 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5406 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5408 /* Mark the state dirty until we have nicer tracking
5409 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5412 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5413 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5414 This
->stateBlock
->streamIsUP
= TRUE
;
5415 This
->stateBlock
->baseVertexIndex
= 0;
5416 This
->up_strided
= DrawPrimStrideData
;
5417 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5418 This
->up_strided
= NULL
;
5422 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5423 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5424 * not callable by the app directly no parameter validation checks are needed here.
5426 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5427 WINED3DLOCKED_BOX src
;
5428 WINED3DLOCKED_BOX dst
;
5430 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5432 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5433 * dirtification to improve loading performance.
5435 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5436 if(FAILED(hr
)) return hr
;
5437 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5439 IWineD3DVolume_UnlockBox(pSourceVolume
);
5443 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5445 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5447 IWineD3DVolume_UnlockBox(pSourceVolume
);
5449 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5454 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5455 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5456 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5457 HRESULT hr
= WINED3D_OK
;
5458 WINED3DRESOURCETYPE sourceType
;
5459 WINED3DRESOURCETYPE destinationType
;
5462 /* TODO: think about moving the code into IWineD3DBaseTexture */
5464 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5466 /* verify that the source and destination textures aren't NULL */
5467 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5468 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5469 This
, pSourceTexture
, pDestinationTexture
);
5470 hr
= WINED3DERR_INVALIDCALL
;
5473 if (pSourceTexture
== pDestinationTexture
) {
5474 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5475 This
, pSourceTexture
, pDestinationTexture
);
5476 hr
= WINED3DERR_INVALIDCALL
;
5478 /* Verify that the source and destination textures are the same type */
5479 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5480 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5482 if (sourceType
!= destinationType
) {
5483 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5485 hr
= WINED3DERR_INVALIDCALL
;
5488 /* check that both textures have the identical numbers of levels */
5489 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5490 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5491 hr
= WINED3DERR_INVALIDCALL
;
5494 if (WINED3D_OK
== hr
) {
5496 /* Make sure that the destination texture is loaded */
5497 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5499 /* Update every surface level of the texture */
5500 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5502 switch (sourceType
) {
5503 case WINED3DRTYPE_TEXTURE
:
5505 IWineD3DSurface
*srcSurface
;
5506 IWineD3DSurface
*destSurface
;
5508 for (i
= 0 ; i
< levels
; ++i
) {
5509 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5510 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5511 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5512 IWineD3DSurface_Release(srcSurface
);
5513 IWineD3DSurface_Release(destSurface
);
5514 if (WINED3D_OK
!= hr
) {
5515 WARN("(%p) : Call to update surface failed\n", This
);
5521 case WINED3DRTYPE_CUBETEXTURE
:
5523 IWineD3DSurface
*srcSurface
;
5524 IWineD3DSurface
*destSurface
;
5525 WINED3DCUBEMAP_FACES faceType
;
5527 for (i
= 0 ; i
< levels
; ++i
) {
5528 /* Update each cube face */
5529 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5530 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5531 if (WINED3D_OK
!= hr
) {
5532 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5534 TRACE("Got srcSurface %p\n", srcSurface
);
5536 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5537 if (WINED3D_OK
!= hr
) {
5538 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5540 TRACE("Got desrSurface %p\n", destSurface
);
5542 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5543 IWineD3DSurface_Release(srcSurface
);
5544 IWineD3DSurface_Release(destSurface
);
5545 if (WINED3D_OK
!= hr
) {
5546 WARN("(%p) : Call to update surface failed\n", This
);
5554 case WINED3DRTYPE_VOLUMETEXTURE
:
5556 IWineD3DVolume
*srcVolume
= NULL
;
5557 IWineD3DVolume
*destVolume
= NULL
;
5559 for (i
= 0 ; i
< levels
; ++i
) {
5560 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5561 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5562 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5563 IWineD3DVolume_Release(srcVolume
);
5564 IWineD3DVolume_Release(destVolume
);
5565 if (WINED3D_OK
!= hr
) {
5566 WARN("(%p) : Call to update volume failed\n", This
);
5574 FIXME("(%p) : Unsupported source and destination type\n", This
);
5575 hr
= WINED3DERR_INVALIDCALL
;
5582 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5583 IWineD3DSwapChain
*swapChain
;
5585 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5586 if(hr
== WINED3D_OK
) {
5587 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5588 IWineD3DSwapChain_Release(swapChain
);
5593 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5594 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5595 IWineD3DBaseTextureImpl
*texture
;
5596 const GlPixelFormatDesc
*gl_info
;
5599 TRACE("(%p) : %p\n", This
, pNumPasses
);
5601 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5602 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
5603 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5604 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5606 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
5607 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5608 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5611 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
5612 if(!texture
) continue;
5613 getFormatDescEntry(texture
->resource
.format
, &GLINFO_LOCATION
, &gl_info
);
5614 if(gl_info
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
5616 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
5617 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
5620 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
5621 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
5624 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
5625 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
5626 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
5631 /* return a sensible default */
5634 TRACE("returning D3D_OK\n");
5638 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5642 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5643 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5644 if (texture
&& (texture
->resource
.format
== WINED3DFMT_P8
|| texture
->resource
.format
== WINED3DFMT_A8P8
)) {
5645 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5650 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5651 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5654 PALETTEENTRY
**palettes
;
5656 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5658 if (PaletteNumber
>= MAX_PALETTES
) {
5659 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5660 return WINED3DERR_INVALIDCALL
;
5663 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5664 NewSize
= This
->NumberOfPalettes
;
5667 } while(PaletteNumber
>= NewSize
);
5668 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5670 ERR("Out of memory!\n");
5671 return E_OUTOFMEMORY
;
5673 This
->palettes
= palettes
;
5674 This
->NumberOfPalettes
= NewSize
;
5677 if (!This
->palettes
[PaletteNumber
]) {
5678 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5679 if (!This
->palettes
[PaletteNumber
]) {
5680 ERR("Out of memory!\n");
5681 return E_OUTOFMEMORY
;
5685 for (j
= 0; j
< 256; ++j
) {
5686 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5687 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5688 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5689 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5691 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5692 TRACE("(%p) : returning\n", This
);
5696 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5697 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5699 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5700 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5701 /* What happens in such situation isn't documented; Native seems to silently abort
5702 on such conditions. Return Invalid Call. */
5703 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5704 return WINED3DERR_INVALIDCALL
;
5706 for (j
= 0; j
< 256; ++j
) {
5707 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5708 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5709 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5710 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5712 TRACE("(%p) : returning\n", This
);
5716 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5717 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5718 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5719 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5720 (tested with reference rasterizer). Return Invalid Call. */
5721 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5722 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5723 return WINED3DERR_INVALIDCALL
;
5725 /*TODO: stateblocks */
5726 if (This
->currentPalette
!= PaletteNumber
) {
5727 This
->currentPalette
= PaletteNumber
;
5728 dirtify_p8_texture_samplers(This
);
5730 TRACE("(%p) : returning\n", This
);
5734 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5735 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5736 if (PaletteNumber
== NULL
) {
5737 WARN("(%p) : returning Invalid Call\n", This
);
5738 return WINED3DERR_INVALIDCALL
;
5740 /*TODO: stateblocks */
5741 *PaletteNumber
= This
->currentPalette
;
5742 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5746 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5747 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5748 static BOOL showFixmes
= TRUE
;
5750 FIXME("(%p) : stub\n", This
);
5754 This
->softwareVertexProcessing
= bSoftware
;
5759 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5760 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5761 static BOOL showFixmes
= TRUE
;
5763 FIXME("(%p) : stub\n", This
);
5766 return This
->softwareVertexProcessing
;
5770 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5771 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5772 IWineD3DSwapChain
*swapChain
;
5775 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5777 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5778 if(hr
== WINED3D_OK
){
5779 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5780 IWineD3DSwapChain_Release(swapChain
);
5782 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5788 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5789 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5790 static BOOL showfixmes
= TRUE
;
5791 if(nSegments
!= 0.0f
) {
5793 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5800 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5801 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5802 static BOOL showfixmes
= TRUE
;
5804 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5810 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5811 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5812 /** TODO: remove casts to IWineD3DSurfaceImpl
5813 * NOTE: move code to surface to accomplish this
5814 ****************************************/
5815 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5816 int srcWidth
, srcHeight
;
5817 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5818 WINED3DFORMAT destFormat
, srcFormat
;
5820 int srcLeft
, destLeft
, destTop
;
5821 WINED3DPOOL srcPool
, destPool
;
5823 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5824 glDescriptor
*glDescription
= NULL
;
5828 CONVERT_TYPES convert
= NO_CONVERSION
;
5830 WINED3DSURFACE_DESC winedesc
;
5832 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5833 memset(&winedesc
, 0, sizeof(winedesc
));
5834 winedesc
.Width
= &srcSurfaceWidth
;
5835 winedesc
.Height
= &srcSurfaceHeight
;
5836 winedesc
.Pool
= &srcPool
;
5837 winedesc
.Format
= &srcFormat
;
5839 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5841 winedesc
.Width
= &destSurfaceWidth
;
5842 winedesc
.Height
= &destSurfaceHeight
;
5843 winedesc
.Pool
= &destPool
;
5844 winedesc
.Format
= &destFormat
;
5845 winedesc
.Size
= &destSize
;
5847 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5849 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5850 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5851 return WINED3DERR_INVALIDCALL
;
5854 /* This call loads the opengl surface directly, instead of copying the surface to the
5855 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5856 * copy in sysmem and use regular surface loading.
5858 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5859 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5860 if(convert
!= NO_CONVERSION
) {
5861 return IWineD3DSurface_BltFast(pDestinationSurface
,
5862 pDestPoint
? pDestPoint
->x
: 0,
5863 pDestPoint
? pDestPoint
->y
: 0,
5864 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5867 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5868 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5869 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5871 /* Get the update surface description */
5872 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5875 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5879 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5880 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5881 checkGLcall("glActiveTextureARB");
5884 /* Make sure the surface is loaded and up to date */
5885 IWineD3DSurface_PreLoad(pDestinationSurface
);
5886 IWineD3DSurface_BindTexture(pDestinationSurface
);
5888 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5890 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5891 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5892 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5893 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5894 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5895 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5898 /* This function doesn't support compressed textures
5899 the pitch is just bytesPerPixel * width */
5900 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5901 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5902 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5903 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5905 /* TODO DXT formats */
5907 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5908 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5910 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5911 This
, glDescription
->level
, destLeft
, destTop
, srcWidth
, srcHeight
, glDescription
->glFormat
,
5912 glDescription
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5915 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5917 /* need to lock the surface to get the data */
5918 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5921 /* TODO: Cube and volume support */
5923 /* not a whole row so we have to do it a line at a time */
5926 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5927 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5929 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5931 glTexSubImage2D(glDescription
->target
5932 ,glDescription
->level
5937 ,glDescription
->glFormat
5938 ,glDescription
->glType
5939 ,data
/* could be quicker using */
5944 } else { /* Full width, so just write out the whole texture */
5945 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5947 if (WINED3DFMT_DXT1
== destFormat
||
5948 WINED3DFMT_DXT2
== destFormat
||
5949 WINED3DFMT_DXT3
== destFormat
||
5950 WINED3DFMT_DXT4
== destFormat
||
5951 WINED3DFMT_DXT5
== destFormat
) {
5952 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5953 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5954 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5955 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5956 } if (destFormat
!= srcFormat
) {
5957 FIXME("Updating mixed format compressed texture is not curretly support\n");
5959 GL_EXTCALL(glCompressedTexImage2DARB(glDescription
->target
, glDescription
->level
,
5960 glDescription
->glFormatInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5963 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5968 glTexSubImage2D(glDescription
->target
, glDescription
->level
, destLeft
, destTop
,
5969 srcWidth
, srcHeight
, glDescription
->glFormat
, glDescription
->glType
, data
);
5972 checkGLcall("glTexSubImage2D");
5976 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5977 sampler
= This
->rev_tex_unit_map
[0];
5978 if (sampler
!= -1) {
5979 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5985 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5986 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5987 struct WineD3DRectPatch
*patch
;
5991 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5993 if(!(Handle
|| pRectPatchInfo
)) {
5994 /* TODO: Write a test for the return value, thus the FIXME */
5995 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5996 return WINED3DERR_INVALIDCALL
;
6000 i
= PATCHMAP_HASHFUNC(Handle
);
6002 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6003 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6004 if(patch
->Handle
== Handle
) {
6011 TRACE("Patch does not exist. Creating a new one\n");
6012 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6013 patch
->Handle
= Handle
;
6014 list_add_head(&This
->patches
[i
], &patch
->entry
);
6016 TRACE("Found existing patch %p\n", patch
);
6019 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6020 * attributes we have to tesselate, read back, and draw. This needs a patch
6021 * management structure instance. Create one.
6023 * A possible improvement is to check if a vertex shader is used, and if not directly
6026 FIXME("Drawing an uncached patch. This is slow\n");
6027 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6030 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
6031 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
6032 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
6034 TRACE("Tesselation density or patch info changed, retesselating\n");
6036 if(pRectPatchInfo
) {
6037 patch
->RectPatchInfo
= *pRectPatchInfo
;
6039 patch
->numSegs
[0] = pNumSegs
[0];
6040 patch
->numSegs
[1] = pNumSegs
[1];
6041 patch
->numSegs
[2] = pNumSegs
[2];
6042 patch
->numSegs
[3] = pNumSegs
[3];
6044 hr
= tesselate_rectpatch(This
, patch
);
6046 WARN("Patch tesselation failed\n");
6048 /* Do not release the handle to store the params of the patch */
6050 HeapFree(GetProcessHeap(), 0, patch
);
6056 This
->currentPatch
= patch
;
6057 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
6058 This
->currentPatch
= NULL
;
6060 /* Destroy uncached patches */
6062 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6063 HeapFree(GetProcessHeap(), 0, patch
);
6068 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
6069 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6070 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
6071 FIXME("(%p) : Stub\n", This
);
6075 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
6076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6078 struct WineD3DRectPatch
*patch
;
6080 TRACE("(%p) Handle(%d)\n", This
, Handle
);
6082 i
= PATCHMAP_HASHFUNC(Handle
);
6083 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6084 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6085 if(patch
->Handle
== Handle
) {
6086 TRACE("Deleting patch %p\n", patch
);
6087 list_remove(&patch
->entry
);
6088 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6089 HeapFree(GetProcessHeap(), 0, patch
);
6094 /* TODO: Write a test for the return value */
6095 FIXME("Attempt to destroy nonexistent patch\n");
6096 return WINED3DERR_INVALIDCALL
;
6099 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6101 IWineD3DSwapChain
*swapchain
;
6103 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6104 if (SUCCEEDED(hr
)) {
6105 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6112 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
6113 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6114 IWineD3DSwapChain
*swapchain
;
6116 swapchain
= get_swapchain(surface
);
6120 TRACE("Surface %p is onscreen\n", surface
);
6122 ActivateContext(This
, surface
, CTXUSAGE_RESOURCELOAD
);
6124 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6125 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6126 glDrawBuffer(buffer
);
6127 checkGLcall("glDrawBuffer()");
6129 TRACE("Surface %p is offscreen\n", surface
);
6131 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6133 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6134 context_attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6135 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6136 checkGLcall("glFramebufferRenderbufferEXT");
6140 glEnable(GL_SCISSOR_TEST
);
6142 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6144 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6145 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6147 checkGLcall("glScissor");
6148 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
6150 glDisable(GL_SCISSOR_TEST
);
6152 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6154 glDisable(GL_BLEND
);
6155 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
6157 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6158 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6160 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
6161 glClear(GL_COLOR_BUFFER_BIT
);
6162 checkGLcall("glClear");
6164 if (This
->activeContext
->current_fbo
) {
6165 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6167 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6168 checkGLcall("glBindFramebuffer()");
6171 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6172 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6173 glDrawBuffer(GL_BACK
);
6174 checkGLcall("glDrawBuffer()");
6180 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6181 unsigned int r
, g
, b
, a
;
6184 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6185 destfmt
== WINED3DFMT_R8G8B8
)
6188 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6190 a
= (color
& 0xff000000) >> 24;
6191 r
= (color
& 0x00ff0000) >> 16;
6192 g
= (color
& 0x0000ff00) >> 8;
6193 b
= (color
& 0x000000ff) >> 0;
6197 case WINED3DFMT_R5G6B5
:
6198 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6205 TRACE("Returning %08x\n", ret
);
6208 case WINED3DFMT_X1R5G5B5
:
6209 case WINED3DFMT_A1R5G5B5
:
6218 TRACE("Returning %08x\n", ret
);
6222 TRACE("Returning %08x\n", a
);
6225 case WINED3DFMT_X4R4G4B4
:
6226 case WINED3DFMT_A4R4G4B4
:
6235 TRACE("Returning %08x\n", ret
);
6238 case WINED3DFMT_R3G3B2
:
6245 TRACE("Returning %08x\n", ret
);
6248 case WINED3DFMT_X8B8G8R8
:
6249 case WINED3DFMT_A8B8G8R8
:
6254 TRACE("Returning %08x\n", ret
);
6257 case WINED3DFMT_A2R10G10B10
:
6259 r
= (r
* 1024) / 256;
6260 g
= (g
* 1024) / 256;
6261 b
= (b
* 1024) / 256;
6266 TRACE("Returning %08x\n", ret
);
6269 case WINED3DFMT_A2B10G10R10
:
6271 r
= (r
* 1024) / 256;
6272 g
= (g
* 1024) / 256;
6273 b
= (b
* 1024) / 256;
6278 TRACE("Returning %08x\n", ret
);
6282 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6287 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6288 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6289 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6291 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6293 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6294 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6295 return WINED3DERR_INVALIDCALL
;
6298 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6299 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6302 /* Just forward this to the DirectDraw blitting engine */
6303 memset(&BltFx
, 0, sizeof(BltFx
));
6304 BltFx
.dwSize
= sizeof(BltFx
);
6305 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6306 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6310 /* rendertarget and depth stencil functions */
6311 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6312 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6314 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6315 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6316 return WINED3DERR_INVALIDCALL
;
6319 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6320 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6321 /* Note inc ref on returned surface */
6322 if(*ppRenderTarget
!= NULL
)
6323 IWineD3DSurface_AddRef(*ppRenderTarget
);
6327 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6329 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6330 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6331 IWineD3DSwapChainImpl
*Swapchain
;
6334 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6336 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6337 if(hr
!= WINED3D_OK
) {
6338 ERR("Can't get the swapchain\n");
6342 /* Make sure to release the swapchain */
6343 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6345 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6346 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6347 return WINED3DERR_INVALIDCALL
;
6349 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6350 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6351 return WINED3DERR_INVALIDCALL
;
6354 if(Swapchain
->frontBuffer
!= Front
) {
6355 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6357 if(Swapchain
->frontBuffer
)
6358 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6359 Swapchain
->frontBuffer
= Front
;
6361 if(Swapchain
->frontBuffer
) {
6362 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6366 if(Back
&& !Swapchain
->backBuffer
) {
6367 /* We need memory for the back buffer array - only one back buffer this way */
6368 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6369 if(!Swapchain
->backBuffer
) {
6370 ERR("Out of memory\n");
6371 return E_OUTOFMEMORY
;
6375 if(Swapchain
->backBuffer
[0] != Back
) {
6376 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6378 /* What to do about the context here in the case of multithreading? Not sure.
6379 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6382 if(!Swapchain
->backBuffer
[0]) {
6383 /* GL was told to draw to the front buffer at creation,
6386 glDrawBuffer(GL_BACK
);
6387 checkGLcall("glDrawBuffer(GL_BACK)");
6388 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6389 Swapchain
->presentParms
.BackBufferCount
= 1;
6391 /* That makes problems - disable for now */
6392 /* glDrawBuffer(GL_FRONT); */
6393 checkGLcall("glDrawBuffer(GL_FRONT)");
6394 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6395 Swapchain
->presentParms
.BackBufferCount
= 0;
6399 if(Swapchain
->backBuffer
[0])
6400 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6401 Swapchain
->backBuffer
[0] = Back
;
6403 if(Swapchain
->backBuffer
[0]) {
6404 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6406 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6407 Swapchain
->backBuffer
= NULL
;
6415 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6416 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6417 *ppZStencilSurface
= This
->stencilBufferTarget
;
6418 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6420 if(*ppZStencilSurface
!= NULL
) {
6421 /* Note inc ref on returned surface */
6422 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6425 return WINED3DERR_NOTFOUND
;
6429 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6430 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6431 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6432 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6433 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6435 POINT offset
= {0, 0};
6437 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6438 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6439 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6440 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6443 case WINED3DTEXF_LINEAR
:
6444 gl_filter
= GL_LINEAR
;
6448 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6449 case WINED3DTEXF_NONE
:
6450 case WINED3DTEXF_POINT
:
6451 gl_filter
= GL_NEAREST
;
6455 /* Attach src surface to src fbo */
6456 src_swapchain
= get_swapchain(src_surface
);
6457 if (src_swapchain
) {
6458 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6460 TRACE("Source surface %p is onscreen\n", src_surface
);
6461 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6462 /* Make sure the drawable is up to date. In the offscreen case
6463 * attach_surface_fbo() implicitly takes care of this. */
6464 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6466 if(buffer
== GL_FRONT
) {
6469 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
6470 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
6471 h
= windowsize
.bottom
- windowsize
.top
;
6472 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6473 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6474 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6476 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6477 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6481 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6482 glReadBuffer(buffer
);
6483 checkGLcall("glReadBuffer()");
6485 TRACE("Source surface %p is offscreen\n", src_surface
);
6487 context_bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->activeContext
->src_fbo
);
6488 context_attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6489 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6490 checkGLcall("glReadBuffer()");
6491 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6492 checkGLcall("glFramebufferRenderbufferEXT");
6496 /* Attach dst surface to dst fbo */
6497 dst_swapchain
= get_swapchain(dst_surface
);
6498 if (dst_swapchain
) {
6499 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6501 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6502 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6503 /* Make sure the drawable is up to date. In the offscreen case
6504 * attach_surface_fbo() implicitly takes care of this. */
6505 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6507 if(buffer
== GL_FRONT
) {
6510 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
6511 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
6512 h
= windowsize
.bottom
- windowsize
.top
;
6513 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6514 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6515 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6517 /* Screen coords = window coords, surface height = window height */
6518 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6519 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6523 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6524 glDrawBuffer(buffer
);
6525 checkGLcall("glDrawBuffer()");
6527 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6529 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6530 if(!src_swapchain
) {
6531 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6535 context_bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6536 context_attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6537 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6538 checkGLcall("glDrawBuffer()");
6539 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6540 checkGLcall("glFramebufferRenderbufferEXT");
6542 glDisable(GL_SCISSOR_TEST
);
6543 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6546 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6547 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6548 checkGLcall("glBlitFramebuffer()");
6550 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6551 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6552 checkGLcall("glBlitFramebuffer()");
6555 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6557 if (This
->activeContext
->current_fbo
) {
6558 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6560 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6561 checkGLcall("glBindFramebuffer()");
6564 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6565 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6566 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6567 glDrawBuffer(GL_BACK
);
6568 checkGLcall("glDrawBuffer()");
6573 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6574 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6575 WINED3DVIEWPORT viewport
;
6577 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6579 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6580 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6581 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6582 return WINED3DERR_INVALIDCALL
;
6585 /* MSDN says that null disables the render target
6586 but a device must always be associated with a render target
6587 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6589 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6590 FIXME("Trying to set render target 0 to NULL\n");
6591 return WINED3DERR_INVALIDCALL
;
6593 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6594 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
);
6595 return WINED3DERR_INVALIDCALL
;
6598 /* If we are trying to set what we already have, don't bother */
6599 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6600 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6603 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6604 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6605 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6607 /* Render target 0 is special */
6608 if(RenderTargetIndex
== 0) {
6609 /* Finally, reset the viewport as the MSDN states. */
6610 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6611 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6614 viewport
.MaxZ
= 1.0f
;
6615 viewport
.MinZ
= 0.0f
;
6616 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6617 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6618 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6620 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6625 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6626 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6627 HRESULT hr
= WINED3D_OK
;
6628 IWineD3DSurface
*tmp
;
6630 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6632 if (pNewZStencil
== This
->stencilBufferTarget
) {
6633 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6635 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6636 * depending on the renter target implementation being used.
6637 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6638 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6639 * stencil buffer and incur an extra memory overhead
6640 ******************************************************/
6642 if (This
->stencilBufferTarget
) {
6643 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6644 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
6645 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
6647 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6648 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6649 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6653 tmp
= This
->stencilBufferTarget
;
6654 This
->stencilBufferTarget
= pNewZStencil
;
6655 /* should we be calling the parent or the wined3d surface? */
6656 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6657 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6660 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6661 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6662 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6663 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6664 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6671 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6672 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6673 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6674 /* TODO: the use of Impl is deprecated. */
6675 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6676 WINED3DLOCKED_RECT lockedRect
;
6678 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6680 /* some basic validation checks */
6681 if(This
->cursorTexture
) {
6682 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6684 glDeleteTextures(1, &This
->cursorTexture
);
6686 This
->cursorTexture
= 0;
6689 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6690 This
->haveHardwareCursor
= TRUE
;
6692 This
->haveHardwareCursor
= FALSE
;
6695 WINED3DLOCKED_RECT rect
;
6697 /* MSDN: Cursor must be A8R8G8B8 */
6698 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6699 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6700 return WINED3DERR_INVALIDCALL
;
6703 /* MSDN: Cursor must be smaller than the display mode */
6704 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6705 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6706 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
);
6707 return WINED3DERR_INVALIDCALL
;
6710 if (!This
->haveHardwareCursor
) {
6711 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6713 /* Do not store the surface's pointer because the application may
6714 * release it after setting the cursor image. Windows doesn't
6715 * addref the set surface, so we can't do this either without
6716 * creating circular refcount dependencies. Copy out the gl texture
6719 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6720 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6721 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6723 const GlPixelFormatDesc
*glDesc
;
6724 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6725 char *mem
, *bits
= (char *)rect
.pBits
;
6726 GLint intfmt
= glDesc
->glInternal
;
6727 GLint format
= glDesc
->glFormat
;
6728 GLint type
= glDesc
->glType
;
6729 INT height
= This
->cursorHeight
;
6730 INT width
= This
->cursorWidth
;
6731 INT bpp
= tableEntry
->bpp
;
6734 /* Reformat the texture memory (pitch and width can be
6736 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6737 for(i
= 0; i
< height
; i
++)
6738 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6739 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6742 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6743 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6744 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6747 /* Make sure that a proper texture unit is selected */
6748 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6749 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6750 checkGLcall("glActiveTextureARB");
6752 sampler
= This
->rev_tex_unit_map
[0];
6753 if (sampler
!= -1) {
6754 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6756 /* Create a new cursor texture */
6757 glGenTextures(1, &This
->cursorTexture
);
6758 checkGLcall("glGenTextures");
6759 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6760 checkGLcall("glBindTexture");
6761 /* Copy the bitmap memory into the cursor texture */
6762 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6763 HeapFree(GetProcessHeap(), 0, mem
);
6764 checkGLcall("glTexImage2D");
6766 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6767 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6768 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6775 FIXME("A cursor texture was not returned.\n");
6776 This
->cursorTexture
= 0;
6781 /* Draw a hardware cursor */
6782 ICONINFO cursorInfo
;
6784 /* Create and clear maskBits because it is not needed for
6785 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6787 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6788 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6789 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6790 WINED3DLOCK_NO_DIRTY_UPDATE
|
6791 WINED3DLOCK_READONLY
6793 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6794 pSur
->currentDesc
.Height
);
6796 cursorInfo
.fIcon
= FALSE
;
6797 cursorInfo
.xHotspot
= XHotSpot
;
6798 cursorInfo
.yHotspot
= YHotSpot
;
6799 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6800 pSur
->currentDesc
.Height
, 1,
6802 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6803 pSur
->currentDesc
.Height
, 1,
6804 32, lockedRect
.pBits
);
6805 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6806 /* Create our cursor and clean up. */
6807 cursor
= CreateIconIndirect(&cursorInfo
);
6809 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6810 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6811 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6812 This
->hardwareCursor
= cursor
;
6813 HeapFree(GetProcessHeap(), 0, maskBits
);
6817 This
->xHotSpot
= XHotSpot
;
6818 This
->yHotSpot
= YHotSpot
;
6822 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6823 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6824 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6826 This
->xScreenSpace
= XScreenSpace
;
6827 This
->yScreenSpace
= YScreenSpace
;
6833 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6834 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6835 BOOL oldVisible
= This
->bCursorVisible
;
6838 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6841 * When ShowCursor is first called it should make the cursor appear at the OS's last
6842 * known cursor position. Because of this, some applications just repetitively call
6843 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6846 This
->xScreenSpace
= pt
.x
;
6847 This
->yScreenSpace
= pt
.y
;
6849 if (This
->haveHardwareCursor
) {
6850 This
->bCursorVisible
= bShow
;
6852 SetCursor(This
->hardwareCursor
);
6858 if (This
->cursorTexture
)
6859 This
->bCursorVisible
= bShow
;
6865 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6866 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6867 IWineD3DResourceImpl
*resource
;
6868 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6870 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6871 switch (This
->state
) {
6874 case WINED3DERR_DEVICELOST
:
6876 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6877 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
6878 return WINED3DERR_DEVICENOTRESET
;
6880 return WINED3DERR_DEVICELOST
;
6882 case WINED3DERR_DRIVERINTERNALERROR
:
6883 return WINED3DERR_DRIVERINTERNALERROR
;
6887 return WINED3DERR_DRIVERINTERNALERROR
;
6891 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6892 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6893 /** FIXME: Resource tracking needs to be done,
6894 * The closes we can do to this is set the priorities of all managed textures low
6895 * and then reset them.
6896 ***********************************************************/
6897 FIXME("(%p) : stub\n", This
);
6901 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6902 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6904 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6905 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6906 /* Release the DC */
6907 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6908 DeleteDC(surface
->hDC
);
6909 /* Release the DIB section */
6910 DeleteObject(surface
->dib
.DIBsection
);
6911 surface
->dib
.bitmap_data
= NULL
;
6912 surface
->resource
.allocatedMemory
= NULL
;
6913 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6915 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6916 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6917 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
6918 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
6919 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6920 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6922 surface
->pow2Width
= surface
->pow2Height
= 1;
6923 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6924 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6926 surface
->glRect
.left
= 0;
6927 surface
->glRect
.top
= 0;
6928 surface
->glRect
.right
= surface
->pow2Width
;
6929 surface
->glRect
.bottom
= surface
->pow2Height
;
6931 if(surface
->glDescription
.textureName
) {
6932 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6934 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6936 surface
->glDescription
.textureName
= 0;
6937 surface
->Flags
&= ~SFLAG_CLIENT
;
6939 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6940 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6941 surface
->Flags
|= SFLAG_NONPOW2
;
6943 surface
->Flags
&= ~SFLAG_NONPOW2
;
6945 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6946 surface
->resource
.allocatedMemory
= NULL
;
6947 surface
->resource
.heapMemory
= NULL
;
6948 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6949 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6950 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
6951 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
6953 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
6957 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6958 TRACE("Unloading resource %p\n", resource
);
6959 IWineD3DResource_UnLoad(resource
);
6960 IWineD3DResource_Release(resource
);
6964 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, WINED3DPRESENT_PARAMETERS
*pp
) {
6966 WINED3DDISPLAYMODE m
;
6969 /* All Windowed modes are supported, as is leaving the current mode */
6970 if(pp
->Windowed
) return TRUE
;
6971 if(!pp
->BackBufferWidth
) return TRUE
;
6972 if(!pp
->BackBufferHeight
) return TRUE
;
6974 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
6975 for(i
= 0; i
< count
; i
++) {
6976 memset(&m
, 0, sizeof(m
));
6977 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
6979 ERR("EnumAdapterModes failed\n");
6981 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6982 /* Mode found, it is supported */
6986 /* Mode not found -> not supported */
6990 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6991 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6992 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6994 IWineD3DBaseShaderImpl
*shader
;
6996 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6997 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6998 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
7002 if(This
->depth_blt_texture
) {
7003 glDeleteTextures(1, &This
->depth_blt_texture
);
7004 This
->depth_blt_texture
= 0;
7006 if (This
->depth_blt_rb
) {
7007 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
7008 This
->depth_blt_rb
= 0;
7009 This
->depth_blt_rb_w
= 0;
7010 This
->depth_blt_rb_h
= 0;
7012 This
->blitter
->free_private(iface
);
7013 This
->frag_pipe
->free_private(iface
);
7014 This
->shader_backend
->shader_free_private(iface
);
7016 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
7017 /* Textures are recreated below */
7018 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
7019 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7020 This
->dummyTextureName
[i
] = 0;
7024 while(This
->numContexts
) {
7025 DestroyContext(This
, This
->contexts
[0]);
7027 This
->activeContext
= NULL
;
7028 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
7029 swapchain
->context
= NULL
;
7030 swapchain
->num_contexts
= 0;
7033 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
7034 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7035 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
7037 IWineD3DSurfaceImpl
*target
;
7039 /* Recreate the primary swapchain's context */
7040 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
7041 if(swapchain
->backBuffer
) {
7042 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
7044 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
7046 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
7047 &swapchain
->presentParms
);
7048 swapchain
->num_contexts
= 1;
7049 This
->activeContext
= swapchain
->context
[0];
7051 create_dummy_textures(This
);
7053 hr
= This
->shader_backend
->shader_alloc_private(iface
);
7055 ERR("Failed to recreate shader private data\n");
7058 hr
= This
->frag_pipe
->alloc_private(iface
);
7060 TRACE("Fragment pipeline private data couldn't be allocated\n");
7063 hr
= This
->blitter
->alloc_private(iface
);
7065 TRACE("Blitter private data couldn't be allocated\n");
7072 This
->blitter
->free_private(iface
);
7073 This
->frag_pipe
->free_private(iface
);
7074 This
->shader_backend
->shader_free_private(iface
);
7078 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7079 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7080 IWineD3DSwapChainImpl
*swapchain
;
7082 BOOL DisplayModeChanged
= FALSE
;
7083 WINED3DDISPLAYMODE mode
;
7084 TRACE("(%p)\n", This
);
7086 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7088 ERR("Failed to get the first implicit swapchain\n");
7092 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7093 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7094 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7095 pPresentationParameters
->BackBufferHeight
);
7096 return WINED3DERR_INVALIDCALL
;
7099 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7100 * on an existing gl context, so there's no real need for recreation.
7102 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7104 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7106 TRACE("New params:\n");
7107 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7108 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7109 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7110 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7111 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7112 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7113 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7114 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7115 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7116 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7117 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7118 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7119 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7121 /* No special treatment of these parameters. Just store them */
7122 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7123 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7124 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7125 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7127 /* What to do about these? */
7128 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7129 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7130 ERR("Cannot change the back buffer count yet\n");
7132 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7133 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7134 ERR("Cannot change the back buffer format yet\n");
7136 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7137 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7138 ERR("Cannot change the device window yet\n");
7140 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
7141 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7142 return WINED3DERR_INVALIDCALL
;
7145 /* Reset the depth stencil */
7146 if (pPresentationParameters
->EnableAutoDepthStencil
)
7147 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
7149 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
7151 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
7153 if(pPresentationParameters
->Windowed
) {
7154 mode
.Width
= swapchain
->orig_width
;
7155 mode
.Height
= swapchain
->orig_height
;
7156 mode
.RefreshRate
= 0;
7157 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7159 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7160 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7161 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7162 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7165 /* Should Width == 800 && Height == 0 set 800x600? */
7166 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7167 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7168 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7175 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
7176 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
7180 if(!pPresentationParameters
->Windowed
) {
7181 DisplayModeChanged
= TRUE
;
7183 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7184 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7186 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7187 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7188 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7190 if(This
->auto_depth_stencil_buffer
) {
7191 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7195 /* Now set the new viewport */
7196 IWineD3DDevice_SetViewport(iface
, &vp
);
7199 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7200 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7201 DisplayModeChanged
) {
7203 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7205 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
7206 if(swapchain
->presentParms
.Windowed
) {
7207 /* switch from windowed to fs */
7208 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7209 pPresentationParameters
->BackBufferWidth
,
7210 pPresentationParameters
->BackBufferHeight
);
7212 /* Fullscreen -> fullscreen mode change */
7213 MoveWindow(swapchain
->win_handle
, 0, 0,
7214 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
7217 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
7218 /* Fullscreen -> windowed switch */
7219 IWineD3DDeviceImpl_RestoreWindow(iface
, swapchain
->win_handle
);
7221 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7222 } else if(!pPresentationParameters
->Windowed
) {
7223 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7224 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7225 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7226 * Reset to clear up their mess. Guild Wars also loses the device during that.
7230 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7231 pPresentationParameters
->BackBufferWidth
,
7232 pPresentationParameters
->BackBufferHeight
);
7233 This
->style
= style
;
7234 This
->exStyle
= exStyle
;
7237 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7239 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7242 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
7243 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7245 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7251 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7252 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7253 /** FIXME: always true at the moment **/
7254 if(!bEnableDialogs
) {
7255 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7261 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7262 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7263 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7265 *pParameters
= This
->createParms
;
7269 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7270 IWineD3DSwapChain
*swapchain
;
7272 TRACE("Relaying to swapchain\n");
7274 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7275 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
7276 IWineD3DSwapChain_Release(swapchain
);
7281 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7282 IWineD3DSwapChain
*swapchain
;
7284 TRACE("Relaying to swapchain\n");
7286 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7287 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7288 IWineD3DSwapChain_Release(swapchain
);
7294 /** ********************************************************
7295 * Notification functions
7296 ** ********************************************************/
7297 /** This function must be called in the release of a resource when ref == 0,
7298 * the contents of resource must still be correct,
7299 * any handles to other resource held by the caller must be closed
7300 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7301 *****************************************************/
7302 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7305 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7306 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7309 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7310 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7312 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7314 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7318 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7319 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7320 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
7323 TRACE("(%p) : resource %p\n", This
, resource
);
7325 context_resource_released(iface
, resource
, type
);
7328 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7329 case WINED3DRTYPE_SURFACE
: {
7332 /* Cleanup any FBO attachments if d3d is enabled */
7333 if(This
->d3d_initialized
) {
7334 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7335 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7337 TRACE("Last active render target destroyed\n");
7338 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7339 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7340 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7341 * and the lastActiveRenderTarget member shouldn't matter
7344 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7345 TRACE("Activating primary back buffer\n");
7346 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7347 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7348 /* Single buffering environment */
7349 TRACE("Activating primary front buffer\n");
7350 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7352 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7353 /* Implicit render target destroyed, that means the device is being destroyed
7354 * whatever we set here, it shouldn't matter
7356 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7359 /* May happen during ddraw uninitialization */
7360 TRACE("Render target set, but swapchain does not exist!\n");
7361 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7365 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7366 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
7367 This
->render_targets
[i
] = NULL
;
7370 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
7371 This
->stencilBufferTarget
= NULL
;
7377 case WINED3DRTYPE_TEXTURE
:
7378 case WINED3DRTYPE_CUBETEXTURE
:
7379 case WINED3DRTYPE_VOLUMETEXTURE
:
7380 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7381 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7382 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7383 This
->stateBlock
->textures
[counter
] = NULL
;
7385 if (This
->updateStateBlock
!= This
->stateBlock
){
7386 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7387 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7388 This
->updateStateBlock
->textures
[counter
] = NULL
;
7393 case WINED3DRTYPE_VOLUME
:
7394 /* TODO: nothing really? */
7396 case WINED3DRTYPE_VERTEXBUFFER
:
7397 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7400 TRACE("Cleaning up stream pointers\n");
7402 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7403 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7404 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7406 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7407 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7408 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7409 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7410 /* Set changed flag? */
7413 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) */
7414 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7415 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7416 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7422 case WINED3DRTYPE_INDEXBUFFER
:
7423 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7424 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7425 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7426 This
->updateStateBlock
->pIndexData
= NULL
;
7429 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7430 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7431 This
->stateBlock
->pIndexData
= NULL
;
7437 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7442 /* Remove the resource from the resourceStore */
7443 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7445 TRACE("Resource released\n");
7449 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7450 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7451 IWineD3DResourceImpl
*resource
, *cursor
;
7453 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7455 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7456 TRACE("enumerating resource %p\n", resource
);
7457 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7458 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7459 if(ret
== S_FALSE
) {
7460 TRACE("Canceling enumeration\n");
7467 /**********************************************************
7468 * IWineD3DDevice VTbl follows
7469 **********************************************************/
7471 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7473 /*** IUnknown methods ***/
7474 IWineD3DDeviceImpl_QueryInterface
,
7475 IWineD3DDeviceImpl_AddRef
,
7476 IWineD3DDeviceImpl_Release
,
7477 /*** IWineD3DDevice methods ***/
7478 IWineD3DDeviceImpl_GetParent
,
7479 /*** Creation methods**/
7480 IWineD3DDeviceImpl_CreateVertexBuffer
,
7481 IWineD3DDeviceImpl_CreateIndexBuffer
,
7482 IWineD3DDeviceImpl_CreateStateBlock
,
7483 IWineD3DDeviceImpl_CreateSurface
,
7484 IWineD3DDeviceImpl_CreateTexture
,
7485 IWineD3DDeviceImpl_CreateVolumeTexture
,
7486 IWineD3DDeviceImpl_CreateVolume
,
7487 IWineD3DDeviceImpl_CreateCubeTexture
,
7488 IWineD3DDeviceImpl_CreateQuery
,
7489 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7490 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7491 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7492 IWineD3DDeviceImpl_CreateVertexShader
,
7493 IWineD3DDeviceImpl_CreatePixelShader
,
7494 IWineD3DDeviceImpl_CreatePalette
,
7495 /*** Odd functions **/
7496 IWineD3DDeviceImpl_Init3D
,
7497 IWineD3DDeviceImpl_InitGDI
,
7498 IWineD3DDeviceImpl_Uninit3D
,
7499 IWineD3DDeviceImpl_UninitGDI
,
7500 IWineD3DDeviceImpl_SetMultithreaded
,
7501 IWineD3DDeviceImpl_EvictManagedResources
,
7502 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7503 IWineD3DDeviceImpl_GetBackBuffer
,
7504 IWineD3DDeviceImpl_GetCreationParameters
,
7505 IWineD3DDeviceImpl_GetDeviceCaps
,
7506 IWineD3DDeviceImpl_GetDirect3D
,
7507 IWineD3DDeviceImpl_GetDisplayMode
,
7508 IWineD3DDeviceImpl_SetDisplayMode
,
7509 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7510 IWineD3DDeviceImpl_GetRasterStatus
,
7511 IWineD3DDeviceImpl_GetSwapChain
,
7512 IWineD3DDeviceImpl_Reset
,
7513 IWineD3DDeviceImpl_SetDialogBoxMode
,
7514 IWineD3DDeviceImpl_SetCursorProperties
,
7515 IWineD3DDeviceImpl_SetCursorPosition
,
7516 IWineD3DDeviceImpl_ShowCursor
,
7517 IWineD3DDeviceImpl_TestCooperativeLevel
,
7518 /*** Getters and setters **/
7519 IWineD3DDeviceImpl_SetClipPlane
,
7520 IWineD3DDeviceImpl_GetClipPlane
,
7521 IWineD3DDeviceImpl_SetClipStatus
,
7522 IWineD3DDeviceImpl_GetClipStatus
,
7523 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7524 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7525 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7526 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7527 IWineD3DDeviceImpl_SetFVF
,
7528 IWineD3DDeviceImpl_GetFVF
,
7529 IWineD3DDeviceImpl_SetGammaRamp
,
7530 IWineD3DDeviceImpl_GetGammaRamp
,
7531 IWineD3DDeviceImpl_SetIndices
,
7532 IWineD3DDeviceImpl_GetIndices
,
7533 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7534 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7535 IWineD3DDeviceImpl_SetLight
,
7536 IWineD3DDeviceImpl_GetLight
,
7537 IWineD3DDeviceImpl_SetLightEnable
,
7538 IWineD3DDeviceImpl_GetLightEnable
,
7539 IWineD3DDeviceImpl_SetMaterial
,
7540 IWineD3DDeviceImpl_GetMaterial
,
7541 IWineD3DDeviceImpl_SetNPatchMode
,
7542 IWineD3DDeviceImpl_GetNPatchMode
,
7543 IWineD3DDeviceImpl_SetPaletteEntries
,
7544 IWineD3DDeviceImpl_GetPaletteEntries
,
7545 IWineD3DDeviceImpl_SetPixelShader
,
7546 IWineD3DDeviceImpl_GetPixelShader
,
7547 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7548 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7549 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7550 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7551 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7552 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7553 IWineD3DDeviceImpl_SetRenderState
,
7554 IWineD3DDeviceImpl_GetRenderState
,
7555 IWineD3DDeviceImpl_SetRenderTarget
,
7556 IWineD3DDeviceImpl_GetRenderTarget
,
7557 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7558 IWineD3DDeviceImpl_SetSamplerState
,
7559 IWineD3DDeviceImpl_GetSamplerState
,
7560 IWineD3DDeviceImpl_SetScissorRect
,
7561 IWineD3DDeviceImpl_GetScissorRect
,
7562 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7563 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7564 IWineD3DDeviceImpl_SetStreamSource
,
7565 IWineD3DDeviceImpl_GetStreamSource
,
7566 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7567 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7568 IWineD3DDeviceImpl_SetTexture
,
7569 IWineD3DDeviceImpl_GetTexture
,
7570 IWineD3DDeviceImpl_SetTextureStageState
,
7571 IWineD3DDeviceImpl_GetTextureStageState
,
7572 IWineD3DDeviceImpl_SetTransform
,
7573 IWineD3DDeviceImpl_GetTransform
,
7574 IWineD3DDeviceImpl_SetVertexDeclaration
,
7575 IWineD3DDeviceImpl_GetVertexDeclaration
,
7576 IWineD3DDeviceImpl_SetVertexShader
,
7577 IWineD3DDeviceImpl_GetVertexShader
,
7578 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7579 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7580 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7581 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7582 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7583 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7584 IWineD3DDeviceImpl_SetViewport
,
7585 IWineD3DDeviceImpl_GetViewport
,
7586 IWineD3DDeviceImpl_MultiplyTransform
,
7587 IWineD3DDeviceImpl_ValidateDevice
,
7588 IWineD3DDeviceImpl_ProcessVertices
,
7589 /*** State block ***/
7590 IWineD3DDeviceImpl_BeginStateBlock
,
7591 IWineD3DDeviceImpl_EndStateBlock
,
7592 /*** Scene management ***/
7593 IWineD3DDeviceImpl_BeginScene
,
7594 IWineD3DDeviceImpl_EndScene
,
7595 IWineD3DDeviceImpl_Present
,
7596 IWineD3DDeviceImpl_Clear
,
7598 IWineD3DDeviceImpl_DrawPrimitive
,
7599 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7600 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7601 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7602 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7603 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7604 IWineD3DDeviceImpl_DrawRectPatch
,
7605 IWineD3DDeviceImpl_DrawTriPatch
,
7606 IWineD3DDeviceImpl_DeletePatch
,
7607 IWineD3DDeviceImpl_ColorFill
,
7608 IWineD3DDeviceImpl_UpdateTexture
,
7609 IWineD3DDeviceImpl_UpdateSurface
,
7610 IWineD3DDeviceImpl_GetFrontBufferData
,
7611 /*** object tracking ***/
7612 IWineD3DDeviceImpl_ResourceReleased
,
7613 IWineD3DDeviceImpl_EnumResources
7616 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl
=
7618 /*** IUnknown methods ***/
7619 IWineD3DDeviceImpl_QueryInterface
,
7620 IWineD3DDeviceImpl_AddRef
,
7621 IWineD3DDeviceImpl_Release
,
7622 /*** IWineD3DDevice methods ***/
7623 IWineD3DDeviceImpl_GetParent
,
7624 /*** Creation methods**/
7625 IWineD3DDeviceImpl_CreateVertexBuffer
,
7626 IWineD3DDeviceImpl_CreateIndexBuffer
,
7627 IWineD3DDeviceImpl_CreateStateBlock
,
7628 IWineD3DDeviceImpl_CreateSurface
,
7629 IWineD3DDeviceImpl_CreateTexture
,
7630 IWineD3DDeviceImpl_CreateVolumeTexture
,
7631 IWineD3DDeviceImpl_CreateVolume
,
7632 IWineD3DDeviceImpl_CreateCubeTexture
,
7633 IWineD3DDeviceImpl_CreateQuery
,
7634 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7635 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7636 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7637 IWineD3DDeviceImpl_CreateVertexShader
,
7638 IWineD3DDeviceImpl_CreatePixelShader
,
7639 IWineD3DDeviceImpl_CreatePalette
,
7640 /*** Odd functions **/
7641 IWineD3DDeviceImpl_Init3D
,
7642 IWineD3DDeviceImpl_InitGDI
,
7643 IWineD3DDeviceImpl_Uninit3D
,
7644 IWineD3DDeviceImpl_UninitGDI
,
7645 IWineD3DDeviceImpl_SetMultithreaded
,
7646 IWineD3DDeviceImpl_EvictManagedResources
,
7647 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7648 IWineD3DDeviceImpl_GetBackBuffer
,
7649 IWineD3DDeviceImpl_GetCreationParameters
,
7650 IWineD3DDeviceImpl_GetDeviceCaps
,
7651 IWineD3DDeviceImpl_GetDirect3D
,
7652 IWineD3DDeviceImpl_GetDisplayMode
,
7653 IWineD3DDeviceImpl_SetDisplayMode
,
7654 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7655 IWineD3DDeviceImpl_GetRasterStatus
,
7656 IWineD3DDeviceImpl_GetSwapChain
,
7657 IWineD3DDeviceImpl_Reset
,
7658 IWineD3DDeviceImpl_SetDialogBoxMode
,
7659 IWineD3DDeviceImpl_SetCursorProperties
,
7660 IWineD3DDeviceImpl_SetCursorPosition
,
7661 IWineD3DDeviceImpl_ShowCursor
,
7662 IWineD3DDeviceImpl_TestCooperativeLevel
,
7663 /*** Getters and setters **/
7664 IWineD3DDeviceImpl_SetClipPlane
,
7665 IWineD3DDeviceImpl_GetClipPlane
,
7666 IWineD3DDeviceImpl_SetClipStatus
,
7667 IWineD3DDeviceImpl_GetClipStatus
,
7668 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7669 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7670 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7671 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7672 IWineD3DDeviceImpl_SetFVF
,
7673 IWineD3DDeviceImpl_GetFVF
,
7674 IWineD3DDeviceImpl_SetGammaRamp
,
7675 IWineD3DDeviceImpl_GetGammaRamp
,
7676 IWineD3DDeviceImpl_SetIndices
,
7677 IWineD3DDeviceImpl_GetIndices
,
7678 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7679 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7680 IWineD3DDeviceImpl_SetLight
,
7681 IWineD3DDeviceImpl_GetLight
,
7682 IWineD3DDeviceImpl_SetLightEnable
,
7683 IWineD3DDeviceImpl_GetLightEnable
,
7684 IWineD3DDeviceImpl_SetMaterial
,
7685 IWineD3DDeviceImpl_GetMaterial
,
7686 IWineD3DDeviceImpl_SetNPatchMode
,
7687 IWineD3DDeviceImpl_GetNPatchMode
,
7688 IWineD3DDeviceImpl_SetPaletteEntries
,
7689 IWineD3DDeviceImpl_GetPaletteEntries
,
7690 IWineD3DDeviceImpl_SetPixelShader
,
7691 IWineD3DDeviceImpl_GetPixelShader
,
7692 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7693 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7694 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7695 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7696 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst
,
7697 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7698 IWineD3DDeviceImpl_SetRenderState
,
7699 IWineD3DDeviceImpl_GetRenderState
,
7700 IWineD3DDeviceImpl_SetRenderTarget
,
7701 IWineD3DDeviceImpl_GetRenderTarget
,
7702 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7703 IWineD3DDeviceImpl_SetSamplerState
,
7704 IWineD3DDeviceImpl_GetSamplerState
,
7705 IWineD3DDeviceImpl_SetScissorRect
,
7706 IWineD3DDeviceImpl_GetScissorRect
,
7707 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7708 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7709 IWineD3DDeviceImpl_SetStreamSource
,
7710 IWineD3DDeviceImpl_GetStreamSource
,
7711 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7712 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7713 IWineD3DDeviceImpl_SetTexture
,
7714 IWineD3DDeviceImpl_GetTexture
,
7715 IWineD3DDeviceImpl_SetTextureStageState
,
7716 IWineD3DDeviceImpl_GetTextureStageState
,
7717 IWineD3DDeviceImpl_SetTransform
,
7718 IWineD3DDeviceImpl_GetTransform
,
7719 IWineD3DDeviceImpl_SetVertexDeclaration
,
7720 IWineD3DDeviceImpl_GetVertexDeclaration
,
7721 IWineD3DDeviceImpl_SetVertexShader
,
7722 IWineD3DDeviceImpl_GetVertexShader
,
7723 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7724 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7725 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7726 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7727 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst
,
7728 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7729 IWineD3DDeviceImpl_SetViewport
,
7730 IWineD3DDeviceImpl_GetViewport
,
7731 IWineD3DDeviceImpl_MultiplyTransform
,
7732 IWineD3DDeviceImpl_ValidateDevice
,
7733 IWineD3DDeviceImpl_ProcessVertices
,
7734 /*** State block ***/
7735 IWineD3DDeviceImpl_BeginStateBlock
,
7736 IWineD3DDeviceImpl_EndStateBlock
,
7737 /*** Scene management ***/
7738 IWineD3DDeviceImpl_BeginScene
,
7739 IWineD3DDeviceImpl_EndScene
,
7740 IWineD3DDeviceImpl_Present
,
7741 IWineD3DDeviceImpl_Clear
,
7743 IWineD3DDeviceImpl_DrawPrimitive
,
7744 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7745 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7746 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7747 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7748 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7749 IWineD3DDeviceImpl_DrawRectPatch
,
7750 IWineD3DDeviceImpl_DrawTriPatch
,
7751 IWineD3DDeviceImpl_DeletePatch
,
7752 IWineD3DDeviceImpl_ColorFill
,
7753 IWineD3DDeviceImpl_UpdateTexture
,
7754 IWineD3DDeviceImpl_UpdateSurface
,
7755 IWineD3DDeviceImpl_GetFrontBufferData
,
7756 /*** object tracking ***/
7757 IWineD3DDeviceImpl_ResourceReleased
,
7758 IWineD3DDeviceImpl_EnumResources
7761 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7762 WINED3DRS_ALPHABLENDENABLE
,
7763 WINED3DRS_ALPHAFUNC
,
7764 WINED3DRS_ALPHAREF
,
7765 WINED3DRS_ALPHATESTENABLE
,
7767 WINED3DRS_COLORWRITEENABLE
,
7768 WINED3DRS_DESTBLEND
,
7769 WINED3DRS_DITHERENABLE
,
7770 WINED3DRS_FILLMODE
,
7771 WINED3DRS_FOGDENSITY
,
7773 WINED3DRS_FOGSTART
,
7774 WINED3DRS_LASTPIXEL
,
7775 WINED3DRS_SHADEMODE
,
7776 WINED3DRS_SRCBLEND
,
7777 WINED3DRS_STENCILENABLE
,
7778 WINED3DRS_STENCILFAIL
,
7779 WINED3DRS_STENCILFUNC
,
7780 WINED3DRS_STENCILMASK
,
7781 WINED3DRS_STENCILPASS
,
7782 WINED3DRS_STENCILREF
,
7783 WINED3DRS_STENCILWRITEMASK
,
7784 WINED3DRS_STENCILZFAIL
,
7785 WINED3DRS_TEXTUREFACTOR
,
7796 WINED3DRS_ZWRITEENABLE
7799 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7800 WINED3DTSS_ADDRESSW
,
7801 WINED3DTSS_ALPHAARG0
,
7802 WINED3DTSS_ALPHAARG1
,
7803 WINED3DTSS_ALPHAARG2
,
7804 WINED3DTSS_ALPHAOP
,
7805 WINED3DTSS_BUMPENVLOFFSET
,
7806 WINED3DTSS_BUMPENVLSCALE
,
7807 WINED3DTSS_BUMPENVMAT00
,
7808 WINED3DTSS_BUMPENVMAT01
,
7809 WINED3DTSS_BUMPENVMAT10
,
7810 WINED3DTSS_BUMPENVMAT11
,
7811 WINED3DTSS_COLORARG0
,
7812 WINED3DTSS_COLORARG1
,
7813 WINED3DTSS_COLORARG2
,
7814 WINED3DTSS_COLOROP
,
7815 WINED3DTSS_RESULTARG
,
7816 WINED3DTSS_TEXCOORDINDEX
,
7817 WINED3DTSS_TEXTURETRANSFORMFLAGS
7820 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7821 WINED3DSAMP_ADDRESSU
,
7822 WINED3DSAMP_ADDRESSV
,
7823 WINED3DSAMP_ADDRESSW
,
7824 WINED3DSAMP_BORDERCOLOR
,
7825 WINED3DSAMP_MAGFILTER
,
7826 WINED3DSAMP_MINFILTER
,
7827 WINED3DSAMP_MIPFILTER
,
7828 WINED3DSAMP_MIPMAPLODBIAS
,
7829 WINED3DSAMP_MAXMIPLEVEL
,
7830 WINED3DSAMP_MAXANISOTROPY
,
7831 WINED3DSAMP_SRGBTEXTURE
,
7832 WINED3DSAMP_ELEMENTINDEX
7835 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7837 WINED3DRS_AMBIENTMATERIALSOURCE
,
7838 WINED3DRS_CLIPPING
,
7839 WINED3DRS_CLIPPLANEENABLE
,
7840 WINED3DRS_COLORVERTEX
,
7841 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7842 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7843 WINED3DRS_FOGDENSITY
,
7845 WINED3DRS_FOGSTART
,
7846 WINED3DRS_FOGTABLEMODE
,
7847 WINED3DRS_FOGVERTEXMODE
,
7848 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7849 WINED3DRS_LIGHTING
,
7850 WINED3DRS_LOCALVIEWER
,
7851 WINED3DRS_MULTISAMPLEANTIALIAS
,
7852 WINED3DRS_MULTISAMPLEMASK
,
7853 WINED3DRS_NORMALIZENORMALS
,
7854 WINED3DRS_PATCHEDGESTYLE
,
7855 WINED3DRS_POINTSCALE_A
,
7856 WINED3DRS_POINTSCALE_B
,
7857 WINED3DRS_POINTSCALE_C
,
7858 WINED3DRS_POINTSCALEENABLE
,
7859 WINED3DRS_POINTSIZE
,
7860 WINED3DRS_POINTSIZE_MAX
,
7861 WINED3DRS_POINTSIZE_MIN
,
7862 WINED3DRS_POINTSPRITEENABLE
,
7863 WINED3DRS_RANGEFOGENABLE
,
7864 WINED3DRS_SPECULARMATERIALSOURCE
,
7865 WINED3DRS_TWEENFACTOR
,
7866 WINED3DRS_VERTEXBLEND
,
7867 WINED3DRS_CULLMODE
,
7871 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7872 WINED3DTSS_TEXCOORDINDEX
,
7873 WINED3DTSS_TEXTURETRANSFORMFLAGS
7876 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7877 WINED3DSAMP_DMAPOFFSET
7880 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7881 DWORD rep
= This
->StateTable
[state
].representative
;
7885 WineD3DContext
*context
;
7888 for(i
= 0; i
< This
->numContexts
; i
++) {
7889 context
= This
->contexts
[i
];
7890 if(isStateDirty(context
, rep
)) continue;
7892 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7895 context
->isStateDirty
[idx
] |= (1 << shift
);
7899 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7900 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7901 /* The drawable size of a pbuffer render target is the current pbuffer size
7903 *width
= dev
->pbufferWidth
;
7904 *height
= dev
->pbufferHeight
;
7907 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7908 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7910 *width
= This
->pow2Width
;
7911 *height
= This
->pow2Height
;
7914 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7915 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7916 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7917 * current context's drawable, which is the size of the back buffer of the swapchain
7918 * the active context belongs to. The back buffer of the swapchain is stored as the
7919 * surface the context belongs to.
7921 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
7922 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;