2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
138 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
140 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
141 if (IsEqualGUID(riid
, &IID_IUnknown
)
142 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
143 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
144 IUnknown_AddRef(iface
);
149 return E_NOINTERFACE
;
152 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
154 ULONG refCount
= InterlockedIncrement(&This
->ref
);
156 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
160 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
161 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
162 ULONG refCount
= InterlockedDecrement(&This
->ref
);
164 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This
->resources
)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
173 dumpResources(&This
->resources
);
176 if(This
->contexts
) ERR("Context array not freed!\n");
177 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
178 This
->haveHardwareCursor
= FALSE
;
180 IWineD3D_Release(This
->wineD3D
);
181 This
->wineD3D
= NULL
;
182 HeapFree(GetProcessHeap(), 0, This
);
183 TRACE("Freed device %p\n", This
);
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
193 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
194 *pParent
= This
->parent
;
195 IUnknown_AddRef(This
->parent
);
199 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
200 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
202 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
203 IWineD3DVertexBufferImpl
*object
;
204 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
205 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer
= NULL
;
211 return WINED3DERR_INVALIDCALL
;
212 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer
= NULL
;
218 return WINED3DERR_INVALIDCALL
;
221 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
223 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
224 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion
<= 7 && conv
) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
253 object
->Flags
|= VBFLAG_CREATEVBO
;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
259 GLenum error
, glUsage
;
260 TRACE("Creating VBO for Index Buffer %p\n", object
);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
273 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
274 error
= glGetError();
275 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
281 error
= glGetError();
282 if(error
!= GL_NO_ERROR
) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage
= GL_STATIC_DRAW_ARB
;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
292 error
= glGetError();
293 if(error
!= GL_NO_ERROR
) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
298 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
308 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
309 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
310 HANDLE
*sharedHandle
, IUnknown
*parent
) {
311 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
312 IWineD3DIndexBufferImpl
*object
;
313 TRACE("(%p) Creating index buffer\n", This
);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
318 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
319 CreateIndexBufferVBO(This
, object
);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
323 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
324 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
329 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
332 IWineD3DStateBlockImpl
*object
;
336 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
337 object
->blockType
= Type
;
339 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
340 list_init(&object
->lightMap
[i
]);
343 temp_result
= allocate_shader_constants(object
);
344 if (FAILED(temp_result
))
346 HeapFree(GetProcessHeap(), 0, object
);
350 /* Special case - Used during initialization to produce a placeholder stateblock
351 so other functions called can update a state block */
352 if (Type
== WINED3DSBT_INIT
) {
353 /* Don't bother increasing the reference count otherwise a device will never
354 be freed due to circular dependencies */
358 /* Otherwise, might as well set the whole state block to the appropriate values */
359 if (This
->stateBlock
!= NULL
)
360 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
362 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
364 /* Reset the ref and type after kludging it */
365 object
->wineD3DDevice
= This
;
367 object
->blockType
= Type
;
369 TRACE("Updating changed flags appropriate for type %d\n", Type
);
371 if (Type
== WINED3DSBT_ALL
) {
373 TRACE("ALL => Pretend everything has changed\n");
374 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
376 /* Lights are not part of the changed / set structure */
377 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
379 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
380 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
381 light
->changed
= TRUE
;
382 light
->enabledChanged
= TRUE
;
385 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
386 object
->contained_render_states
[j
- 1] = j
;
388 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
389 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
390 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
391 object
->contained_transform_states
[j
- 1] = j
;
393 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
394 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
395 object
->contained_vs_consts_f
[j
] = j
;
397 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
398 for(j
= 0; j
< MAX_CONST_I
; j
++) {
399 object
->contained_vs_consts_i
[j
] = j
;
401 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
402 for(j
= 0; j
< MAX_CONST_B
; j
++) {
403 object
->contained_vs_consts_b
[j
] = j
;
405 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
406 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
407 object
->contained_ps_consts_f
[j
] = j
;
409 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
410 for(j
= 0; j
< MAX_CONST_I
; j
++) {
411 object
->contained_ps_consts_i
[j
] = j
;
413 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
414 for(j
= 0; j
< MAX_CONST_B
; j
++) {
415 object
->contained_ps_consts_b
[j
] = j
;
417 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
418 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
419 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
420 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
421 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
422 object
->num_contained_tss_states
++;
425 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
426 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
427 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
428 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
429 object
->num_contained_sampler_states
++;
433 for(i
= 0; i
< MAX_STREAMS
; i
++) {
434 if(object
->streamSource
[i
]) {
435 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
438 if(object
->pIndexData
) {
439 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
441 if(object
->vertexShader
) {
442 IWineD3DVertexShader_AddRef(object
->vertexShader
);
444 if(object
->pixelShader
) {
445 IWineD3DPixelShader_AddRef(object
->pixelShader
);
448 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
450 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
451 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
453 object
->changed
.pixelShader
= TRUE
;
455 /* Pixel Shader Constants */
456 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
) {
457 object
->contained_ps_consts_f
[i
] = i
;
458 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
460 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
461 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
462 object
->contained_ps_consts_b
[i
] = i
;
463 object
->changed
.pixelShaderConstantsB
|= (1 << i
);
465 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
466 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
467 object
->contained_ps_consts_i
[i
] = i
;
468 object
->changed
.pixelShaderConstantsI
|= (1 << i
);
470 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
472 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
473 DWORD rs
= SavedPixelStates_R
[i
];
474 object
->changed
.renderState
[rs
>> 5] |= 1 << (rs
& 0x1f);
475 object
->contained_render_states
[i
] = rs
;
477 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
478 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
479 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
480 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
481 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
482 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
483 object
->num_contained_tss_states
++;
486 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
487 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
488 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
489 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
490 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
491 object
->num_contained_sampler_states
++;
494 if(object
->pixelShader
) {
495 IWineD3DPixelShader_AddRef(object
->pixelShader
);
498 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
499 * on them. This makes releasing the buffer easier
501 for(i
= 0; i
< MAX_STREAMS
; i
++) {
502 object
->streamSource
[i
] = NULL
;
504 object
->pIndexData
= NULL
;
505 object
->vertexShader
= NULL
;
507 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
509 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
510 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
512 object
->changed
.vertexShader
= TRUE
;
514 /* Vertex Shader Constants */
515 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
516 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
517 object
->contained_vs_consts_f
[i
] = i
;
519 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
520 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
521 object
->contained_vs_consts_b
[i
] = i
;
522 object
->changed
.vertexShaderConstantsB
|= (1 << i
);
524 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
525 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
526 object
->contained_vs_consts_i
[i
] = i
;
527 object
->changed
.vertexShaderConstantsI
|= (1 << i
);
529 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
530 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
531 DWORD rs
= SavedVertexStates_R
[i
];
532 object
->changed
.renderState
[rs
>> 5] |= 1 << (rs
& 0x1f);
533 object
->contained_render_states
[i
] = rs
;
535 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
536 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
537 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
538 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
539 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
540 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
541 object
->num_contained_tss_states
++;
544 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
545 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
546 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
547 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
548 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
549 object
->num_contained_sampler_states
++;
553 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
555 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
556 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
557 light
->changed
= TRUE
;
558 light
->enabledChanged
= TRUE
;
562 for(i
= 0; i
< MAX_STREAMS
; i
++) {
563 if(object
->streamSource
[i
]) {
564 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
567 if(object
->vertexShader
) {
568 IWineD3DVertexShader_AddRef(object
->vertexShader
);
570 object
->pIndexData
= NULL
;
571 object
->pixelShader
= NULL
;
573 FIXME("Unrecognized state block type %d\n", Type
);
576 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
580 /* ************************************
582 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
585 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
587 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.
589 ******************************** */
591 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
) {
592 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
593 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
594 unsigned int Size
= 1;
595 const struct GlPixelFormatDesc
*glDesc
;
596 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
598 TRACE("(%p) Create surface\n",This
);
600 /** FIXME: Check ranges on the inputs are valid
603 * [in] Quality level. The valid range is between zero and one less than the level
604 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
605 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
606 * values of paired render targets, depth stencil surfaces, and the MultiSample type
608 *******************************/
613 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
615 * If this flag is set, the contents of the depth stencil buffer will be
616 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
617 * with a different depth surface.
619 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
620 ***************************/
622 if(MultisampleQuality
> 0) {
623 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
624 MultisampleQuality
=0;
627 /** FIXME: Check that the format is supported
629 *******************************/
631 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
632 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
634 *********************************/
635 mul_4w
= (Width
+ 3) & ~3;
636 mul_4h
= (Height
+ 3) & ~3;
637 if (WINED3DFMT_UNKNOWN
== Format
) {
639 } else if (Format
== WINED3DFMT_DXT1
) {
640 /* DXT1 is half byte per pixel */
641 Size
= (mul_4w
* tableEntry
->bpp
* mul_4h
) >> 1;
643 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
644 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
||
645 Format
== WINED3DFMT_ATI2N
) {
646 Size
= (mul_4w
* tableEntry
->bpp
* mul_4h
);
648 /* The pitch is a multiple of 4 bytes */
649 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
653 if(glDesc
->heightscale
!= 0.0) Size
*= glDesc
->heightscale
;
655 /** Create and initialise the surface resource **/
656 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
657 /* "Standalone" surface */
658 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
660 object
->currentDesc
.Width
= Width
;
661 object
->currentDesc
.Height
= Height
;
662 object
->currentDesc
.MultiSampleType
= MultiSample
;
663 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
664 object
->glDescription
.level
= Level
;
665 object
->heightscale
= glDesc
->heightscale
!= 0.0 ? glDesc
->heightscale
: 1.0;
666 list_init(&object
->overlays
);
669 object
->Flags
= SFLAG_NORMCOORD
; /* Default to normalized coords */
670 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
671 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
672 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
675 if (WINED3DFMT_UNKNOWN
!= Format
) {
676 object
->bytesPerPixel
= tableEntry
->bpp
;
678 object
->bytesPerPixel
= 0;
681 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
683 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
685 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
686 * this function is too deep to need to care about things like this.
687 * Levels need to be checked too, and possibly Type since they all affect what can be done.
688 * ****************************************/
690 case WINED3DPOOL_SCRATCH
:
692 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
693 "which are mutually exclusive, setting lockable to TRUE\n");
696 case WINED3DPOOL_SYSTEMMEM
:
697 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
698 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
699 case WINED3DPOOL_MANAGED
:
700 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
701 "Usage of DYNAMIC which are mutually exclusive, not doing "
702 "anything just telling you.\n");
704 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
705 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
706 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
707 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
710 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
714 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
715 FIXME("Trying to create a render target that isn't in the default pool\n");
718 /* mark the texture as dirty so that it gets loaded first time around*/
719 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
720 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
721 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
722 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
724 /* Look at the implementation and set the correct Vtable */
727 /* Check if a 3D adapter is available when creating gl surfaces */
729 ERR("OpenGL surfaces are not available without opengl\n");
730 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
731 HeapFree(GetProcessHeap(), 0, object
);
732 return WINED3DERR_NOTAVAILABLE
;
737 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
741 /* To be sure to catch this */
742 ERR("Unknown requested surface implementation %d!\n", Impl
);
743 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
744 return WINED3DERR_INVALIDCALL
;
747 list_init(&object
->renderbuffers
);
749 /* Call the private setup routine */
750 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
754 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
755 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
756 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
757 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
759 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
760 IWineD3DTextureImpl
*object
;
765 unsigned int pow2Width
;
766 unsigned int pow2Height
;
767 const struct GlPixelFormatDesc
*glDesc
;
768 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
770 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
771 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
772 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
774 /* TODO: It should only be possible to create textures for formats
775 that are reported as supported */
776 if (WINED3DFMT_UNKNOWN
>= Format
) {
777 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
778 return WINED3DERR_INVALIDCALL
;
781 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
782 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
783 object
->width
= Width
;
784 object
->height
= Height
;
786 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
787 object
->baseTexture
.minMipLookup
= minMipLookup
;
788 object
->baseTexture
.magLookup
= magLookup
;
790 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
791 object
->baseTexture
.magLookup
= magLookup_noFilter
;
794 /** Non-power2 support **/
795 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
799 /* Find the nearest pow2 match */
800 pow2Width
= pow2Height
= 1;
801 while (pow2Width
< Width
) pow2Width
<<= 1;
802 while (pow2Height
< Height
) pow2Height
<<= 1;
804 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
806 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
807 HeapFree(GetProcessHeap(), 0, object
);
809 return WINED3DERR_INVALIDCALL
;
816 /** FIXME: add support for real non-power-two if it's provided by the video card **/
817 /* Precalculated scaling for 'faked' non power of two texture coords.
818 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
819 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
820 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
822 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT
) && (Width
!= pow2Width
|| Height
!= pow2Height
)) {
823 object
->baseTexture
.pow2Matrix
[0] = 1.0;
824 object
->baseTexture
.pow2Matrix
[5] = 1.0;
825 object
->baseTexture
.pow2Matrix
[10] = 1.0;
826 object
->baseTexture
.pow2Matrix
[15] = 1.0;
827 object
->target
= GL_TEXTURE_2D
;
828 object
->cond_np2
= TRUE
;
829 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
830 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
831 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
832 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
834 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
835 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
836 object
->baseTexture
.pow2Matrix
[10] = 1.0;
837 object
->baseTexture
.pow2Matrix
[15] = 1.0;
838 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
839 object
->cond_np2
= TRUE
;
840 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
842 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
843 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
844 object
->baseTexture
.pow2Matrix
[10] = 1.0;
845 object
->baseTexture
.pow2Matrix
[15] = 1.0;
846 object
->target
= GL_TEXTURE_2D
;
847 object
->cond_np2
= FALSE
;
849 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
851 /* Calculate levels for mip mapping */
852 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
853 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
854 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
855 return WINED3DERR_INVALIDCALL
;
858 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
859 return WINED3DERR_INVALIDCALL
;
861 object
->baseTexture
.levels
= 1;
862 } else if (Levels
== 0) {
863 object
->baseTexture
.levels
= wined3d_log2i(max(Width
, Height
)) + 1;
864 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
867 /* Generate all the surfaces */
870 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
872 /* use the callback to create the texture surface */
873 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
874 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
875 FIXME("Failed to create surface %p\n", object
);
877 object
->surfaces
[i
] = NULL
;
878 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
884 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
885 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
886 surface_set_texture_target(object
->surfaces
[i
], object
->target
);
887 /* calculate the next mipmap level */
888 tmpW
= max(1, tmpW
>> 1);
889 tmpH
= max(1, tmpH
>> 1);
891 object
->baseTexture
.shader_color_fixup
= glDesc
->color_fixup
;
893 TRACE("(%p) : Created texture %p\n", This
, object
);
897 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
898 UINT Width
, UINT Height
, UINT Depth
,
899 UINT Levels
, DWORD Usage
,
900 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
901 IWineD3DVolumeTexture
**ppVolumeTexture
,
902 HANDLE
*pSharedHandle
, IUnknown
*parent
,
903 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
905 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
906 IWineD3DVolumeTextureImpl
*object
;
911 const struct GlPixelFormatDesc
*glDesc
;
913 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
915 /* TODO: It should only be possible to create textures for formats
916 that are reported as supported */
917 if (WINED3DFMT_UNKNOWN
>= Format
) {
918 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
919 return WINED3DERR_INVALIDCALL
;
921 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
922 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
923 return WINED3DERR_INVALIDCALL
;
926 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
927 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
929 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
930 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
932 /* Is NP2 support for volumes needed? */
933 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
934 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
935 object
->baseTexture
.pow2Matrix
[10] = 1.0;
936 object
->baseTexture
.pow2Matrix
[15] = 1.0;
938 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
939 object
->baseTexture
.minMipLookup
= minMipLookup
;
940 object
->baseTexture
.magLookup
= magLookup
;
942 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
943 object
->baseTexture
.magLookup
= magLookup_noFilter
;
946 /* Calculate levels for mip mapping */
947 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
948 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
949 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
950 return WINED3DERR_INVALIDCALL
;
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL
;
956 object
->baseTexture
.levels
= 1;
957 } else if (Levels
== 0) {
958 object
->baseTexture
.levels
= wined3d_log2i(max(max(Width
, Height
), Depth
)) + 1;
959 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
962 /* Generate all the surfaces */
967 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
970 /* Create the volume */
971 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
972 &object
->volumes
[i
], pSharedHandle
);
975 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
976 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
977 *ppVolumeTexture
= NULL
;
981 /* Set its container to this object */
982 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
984 /* calculate the next mipmap level */
985 tmpW
= max(1, tmpW
>> 1);
986 tmpH
= max(1, tmpH
>> 1);
987 tmpD
= max(1, tmpD
>> 1);
989 object
->baseTexture
.shader_color_fixup
= glDesc
->color_fixup
;
991 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
992 TRACE("(%p) : Created volume texture %p\n", This
, object
);
996 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
997 UINT Width
, UINT Height
, UINT Depth
,
999 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1000 IWineD3DVolume
** ppVolume
,
1001 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1003 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1004 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1005 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1007 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1008 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1009 return WINED3DERR_INVALIDCALL
;
1012 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1014 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1015 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1017 object
->currentDesc
.Width
= Width
;
1018 object
->currentDesc
.Height
= Height
;
1019 object
->currentDesc
.Depth
= Depth
;
1020 object
->bytesPerPixel
= formatDesc
->bpp
;
1022 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1023 object
->lockable
= TRUE
;
1024 object
->locked
= FALSE
;
1025 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1026 object
->dirty
= TRUE
;
1028 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1031 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1032 UINT Levels
, DWORD Usage
,
1033 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1034 IWineD3DCubeTexture
**ppCubeTexture
,
1035 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1036 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1038 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1039 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1043 unsigned int pow2EdgeLength
;
1044 const struct GlPixelFormatDesc
*glDesc
;
1045 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1047 /* TODO: It should only be possible to create textures for formats
1048 that are reported as supported */
1049 if (WINED3DFMT_UNKNOWN
>= Format
) {
1050 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1051 return WINED3DERR_INVALIDCALL
;
1054 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1055 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1056 return WINED3DERR_INVALIDCALL
;
1059 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1060 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1062 TRACE("(%p) Create Cube Texture\n", This
);
1064 /* Find the nearest pow2 match */
1066 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1068 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
1069 /* Precalculated scaling for 'faked' non power of two texture coords */
1070 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
1071 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
1072 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1073 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1075 /* Precalculated scaling for 'faked' non power of two texture coords */
1076 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1077 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1078 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1079 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1082 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
1083 object
->baseTexture
.minMipLookup
= minMipLookup
;
1084 object
->baseTexture
.magLookup
= magLookup
;
1086 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
1087 object
->baseTexture
.magLookup
= magLookup_noFilter
;
1090 /* Calculate levels for mip mapping */
1091 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1092 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1093 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1094 HeapFree(GetProcessHeap(), 0, object
);
1095 *ppCubeTexture
= NULL
;
1097 return WINED3DERR_INVALIDCALL
;
1100 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1101 HeapFree(GetProcessHeap(), 0, object
);
1102 *ppCubeTexture
= NULL
;
1104 return WINED3DERR_INVALIDCALL
;
1106 object
->baseTexture
.levels
= 1;
1107 } else if (Levels
== 0) {
1108 object
->baseTexture
.levels
= wined3d_log2i(EdgeLength
) + 1;
1109 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1112 /* Generate all the surfaces */
1114 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1116 /* Create the 6 faces */
1117 for (j
= 0; j
< 6; j
++) {
1118 static const GLenum cube_targets
[6] = {
1119 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
1120 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
1121 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
1122 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
1123 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
1124 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1127 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1128 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1130 if(hr
!= WINED3D_OK
) {
1134 for (l
= 0; l
< j
; l
++) {
1135 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1137 for (k
= 0; k
< i
; k
++) {
1138 for (l
= 0; l
< 6; l
++) {
1139 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1143 FIXME("(%p) Failed to create surface\n",object
);
1144 HeapFree(GetProcessHeap(),0,object
);
1145 *ppCubeTexture
= NULL
;
1148 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1149 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1150 surface_set_texture_target(object
->surfaces
[j
][i
], cube_targets
[j
]);
1152 tmpW
= max(1, tmpW
>> 1);
1154 object
->baseTexture
.shader_color_fixup
= glDesc
->color_fixup
;
1156 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1157 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1161 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1162 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1163 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1164 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1165 const IWineD3DQueryVtbl
*vtable
;
1167 /* Just a check to see if we support this type of query */
1169 case WINED3DQUERYTYPE_OCCLUSION
:
1170 TRACE("(%p) occlusion query\n", This
);
1171 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1174 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1176 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1179 case WINED3DQUERYTYPE_EVENT
:
1180 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1181 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1182 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1184 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1186 vtable
= &IWineD3DEventQuery_Vtbl
;
1190 case WINED3DQUERYTYPE_VCACHE
:
1191 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1192 case WINED3DQUERYTYPE_VERTEXSTATS
:
1193 case WINED3DQUERYTYPE_TIMESTAMP
:
1194 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1195 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1196 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1197 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1198 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1199 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1200 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1201 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1203 /* Use the base Query vtable until we have a special one for each query */
1204 vtable
= &IWineD3DQuery_Vtbl
;
1205 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1207 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1211 D3DCREATEOBJECTINSTANCE(object
, Query
)
1212 object
->lpVtbl
= vtable
;
1213 object
->type
= Type
;
1214 object
->state
= QUERY_CREATED
;
1215 /* allocated the 'extended' data based on the type of query requested */
1217 case WINED3DQUERYTYPE_OCCLUSION
:
1218 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1219 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1221 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1222 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1224 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
1226 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1230 case WINED3DQUERYTYPE_EVENT
:
1231 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1232 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1234 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
1236 if(GL_SUPPORT(APPLE_FENCE
)) {
1237 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1238 checkGLcall("glGenFencesAPPLE");
1239 } else if(GL_SUPPORT(NV_FENCE
)) {
1240 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1241 checkGLcall("glGenFencesNV");
1246 case WINED3DQUERYTYPE_VCACHE
:
1247 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1248 case WINED3DQUERYTYPE_VERTEXSTATS
:
1249 case WINED3DQUERYTYPE_TIMESTAMP
:
1250 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1251 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1252 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1253 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1254 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1255 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1256 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1257 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1259 object
->extendedData
= 0;
1260 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1262 TRACE("(%p) : Created Query %p\n", This
, object
);
1266 /*****************************************************************************
1267 * IWineD3DDeviceImpl_SetupFullscreenWindow
1269 * Helper function that modifies a HWND's Style and ExStyle for proper
1273 * iface: Pointer to the IWineD3DDevice interface
1274 * window: Window to setup
1276 *****************************************************************************/
1277 static LONG
fullscreen_style(LONG orig_style
) {
1278 LONG style
= orig_style
;
1279 style
&= ~WS_CAPTION
;
1280 style
&= ~WS_THICKFRAME
;
1282 /* Make sure the window is managed, otherwise we won't get keyboard input */
1283 style
|= WS_POPUP
| WS_SYSMENU
;
1288 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1289 LONG exStyle
= orig_exStyle
;
1291 /* Filter out window decorations */
1292 exStyle
&= ~WS_EX_WINDOWEDGE
;
1293 exStyle
&= ~WS_EX_CLIENTEDGE
;
1298 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
) {
1299 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1301 LONG style
, exStyle
;
1302 /* Don't do anything if an original style is stored.
1303 * That shouldn't happen
1305 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1306 if (This
->style
|| This
->exStyle
) {
1307 ERR("(%p): Want to change the window parameters of HWND %p, but "
1308 "another style is stored for restoration afterwards\n", This
, window
);
1311 /* Get the parameters and save them */
1312 style
= GetWindowLongW(window
, GWL_STYLE
);
1313 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1314 This
->style
= style
;
1315 This
->exStyle
= exStyle
;
1317 style
= fullscreen_style(style
);
1318 exStyle
= fullscreen_exStyle(exStyle
);
1320 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1321 This
->style
, This
->exStyle
, style
, exStyle
);
1323 SetWindowLongW(window
, GWL_STYLE
, style
);
1324 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1326 /* Inform the window about the update. */
1327 SetWindowPos(window
, HWND_TOP
, 0, 0,
1328 w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
);
1331 /*****************************************************************************
1332 * IWineD3DDeviceImpl_RestoreWindow
1334 * Helper function that restores a windows' properties when taking it out
1335 * of fullscreen mode
1338 * iface: Pointer to the IWineD3DDevice interface
1339 * window: Window to setup
1341 *****************************************************************************/
1342 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1343 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1344 LONG style
, exStyle
;
1346 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1347 * switch, do nothing
1349 if (!This
->style
&& !This
->exStyle
) return;
1351 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1352 This
, window
, This
->style
, This
->exStyle
);
1354 style
= GetWindowLongW(window
, GWL_STYLE
);
1355 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1357 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1358 * Some applications change it before calling Reset() when switching between windowed and
1359 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1361 if(style
== fullscreen_style(This
->style
) &&
1362 exStyle
== fullscreen_style(This
->exStyle
)) {
1363 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1364 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1367 /* Delete the old values */
1371 /* Inform the window about the update */
1372 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1373 0, 0, 0, 0, /* Pos, Size, ignored */
1374 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1377 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1378 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
* iface
,
1379 WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1380 IUnknown
* parent
, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1381 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
, WINED3DSURFTYPE surface_type
)
1383 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1386 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1388 IUnknown
*bufferParent
;
1389 BOOL displaymode_set
= FALSE
;
1390 WINED3DDISPLAYMODE Mode
;
1391 const StaticPixelFormatDesc
*formatDesc
;
1393 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1395 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1396 * does a device hold a reference to a swap chain giving them a lifetime of the device
1397 * or does the swap chain notify the device of its destruction.
1398 *******************************/
1400 /* Check the params */
1401 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1402 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1403 return WINED3DERR_INVALIDCALL
;
1404 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1405 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");
1408 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1409 switch(surface_type
) {
1411 object
->lpVtbl
= &IWineGDISwapChain_Vtbl
;
1413 case SURFACE_OPENGL
:
1414 object
->lpVtbl
= &IWineD3DSwapChain_Vtbl
;
1416 case SURFACE_UNKNOWN
:
1417 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1418 return WINED3DERR_INVALIDCALL
;
1421 /*********************
1422 * Lookup the window Handle and the relating X window handle
1423 ********************/
1425 /* Setup hwnd we are using, plus which display this equates to */
1426 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1427 if (!object
->win_handle
) {
1428 object
->win_handle
= This
->createParms
.hFocusWindow
;
1430 if(!pPresentationParameters
->Windowed
&& object
->win_handle
) {
1431 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
,
1432 pPresentationParameters
->BackBufferWidth
,
1433 pPresentationParameters
->BackBufferHeight
);
1436 hDc
= GetDC(object
->win_handle
);
1437 TRACE("Using hDc %p\n", hDc
);
1440 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1441 return WINED3DERR_NOTAVAILABLE
;
1444 /* Get info on the current display setup */
1445 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1446 object
->orig_width
= Mode
.Width
;
1447 object
->orig_height
= Mode
.Height
;
1448 object
->orig_fmt
= Mode
.Format
;
1449 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1451 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1452 * then the corresponding dimension of the client area of the hDeviceWindow
1453 * (or the focus window, if hDeviceWindow is NULL) is taken.
1454 **********************/
1456 if (pPresentationParameters
->Windowed
&&
1457 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1458 (pPresentationParameters
->BackBufferHeight
== 0) ||
1459 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1462 GetClientRect(object
->win_handle
, &Rect
);
1464 if (pPresentationParameters
->BackBufferWidth
== 0) {
1465 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1466 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1468 if (pPresentationParameters
->BackBufferHeight
== 0) {
1469 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1470 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1472 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1473 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1474 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1478 /* Put the correct figures in the presentation parameters */
1479 TRACE("Copying across presentation parameters\n");
1480 object
->presentParms
= *pPresentationParameters
;
1482 TRACE("calling rendertarget CB\n");
1483 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1485 object
->presentParms
.BackBufferWidth
,
1486 object
->presentParms
.BackBufferHeight
,
1487 object
->presentParms
.BackBufferFormat
,
1488 object
->presentParms
.MultiSampleType
,
1489 object
->presentParms
.MultiSampleQuality
,
1490 TRUE
/* Lockable */,
1491 &object
->frontBuffer
,
1492 NULL
/* pShared (always null)*/);
1493 if (SUCCEEDED(hr
)) {
1494 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1495 if(surface_type
== SURFACE_OPENGL
) {
1496 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1499 ERR("Failed to create the front buffer\n");
1503 /*********************
1504 * Windowed / Fullscreen
1505 *******************/
1508 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1509 * so we should really check to see if there is a fullscreen swapchain already
1510 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1511 **************************************/
1513 if (!pPresentationParameters
->Windowed
) {
1514 WINED3DDISPLAYMODE mode
;
1517 /* Change the display settings */
1518 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1519 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1520 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1521 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1523 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1524 displaymode_set
= TRUE
;
1528 * Create an opengl context for the display visual
1529 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1530 * use different properties after that point in time. FIXME: How to handle when requested format
1531 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1532 * it chooses is identical to the one already being used!
1533 **********************************/
1534 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1536 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1537 if(!object
->context
) {
1538 ERR("Failed to create the context array\n");
1542 object
->num_contexts
= 1;
1544 if(surface_type
== SURFACE_OPENGL
) {
1545 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1546 if (!object
->context
[0]) {
1547 ERR("Failed to create a new context\n");
1548 hr
= WINED3DERR_NOTAVAILABLE
;
1551 TRACE("Context created (HWND=%p, glContext=%p)\n",
1552 object
->win_handle
, object
->context
[0]->glCtx
);
1556 /*********************
1557 * Create the back, front and stencil buffers
1558 *******************/
1559 if(object
->presentParms
.BackBufferCount
> 0) {
1562 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1563 if(!object
->backBuffer
) {
1564 ERR("Out of memory\n");
1569 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1570 TRACE("calling rendertarget CB\n");
1571 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1573 object
->presentParms
.BackBufferWidth
,
1574 object
->presentParms
.BackBufferHeight
,
1575 object
->presentParms
.BackBufferFormat
,
1576 object
->presentParms
.MultiSampleType
,
1577 object
->presentParms
.MultiSampleQuality
,
1578 TRUE
/* Lockable */,
1579 &object
->backBuffer
[i
],
1580 NULL
/* pShared (always null)*/);
1582 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1584 ERR("Cannot create new back buffer\n");
1587 if(surface_type
== SURFACE_OPENGL
) {
1589 glDrawBuffer(GL_BACK
);
1590 checkGLcall("glDrawBuffer(GL_BACK)");
1595 object
->backBuffer
= NULL
;
1597 /* Single buffering - draw to front buffer */
1598 if(surface_type
== SURFACE_OPENGL
) {
1600 glDrawBuffer(GL_FRONT
);
1601 checkGLcall("glDrawBuffer(GL_FRONT)");
1606 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1607 if (pPresentationParameters
->EnableAutoDepthStencil
&& surface_type
== SURFACE_OPENGL
) {
1608 TRACE("Creating depth stencil buffer\n");
1609 if (This
->auto_depth_stencil_buffer
== NULL
) {
1610 hr
= D3DCB_CreateDepthStencil(This
->parent
,
1612 object
->presentParms
.BackBufferWidth
,
1613 object
->presentParms
.BackBufferHeight
,
1614 object
->presentParms
.AutoDepthStencilFormat
,
1615 object
->presentParms
.MultiSampleType
,
1616 object
->presentParms
.MultiSampleQuality
,
1617 FALSE
/* FIXME: Discard */,
1618 &This
->auto_depth_stencil_buffer
,
1619 NULL
/* pShared (always null)*/ );
1620 if (SUCCEEDED(hr
)) {
1621 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1623 ERR("Failed to create the auto depth stencil\n");
1629 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1631 TRACE("Created swapchain %p\n", object
);
1632 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, pPresentationParameters
->EnableAutoDepthStencil
);
1636 if (displaymode_set
) {
1640 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1643 /* Change the display settings */
1644 memset(&devmode
, 0, sizeof(devmode
));
1645 devmode
.dmSize
= sizeof(devmode
);
1646 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1647 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1648 devmode
.dmPelsWidth
= object
->orig_width
;
1649 devmode
.dmPelsHeight
= object
->orig_height
;
1650 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1653 if (object
->backBuffer
) {
1655 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1656 if(object
->backBuffer
[i
]) {
1657 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1658 IUnknown_Release(bufferParent
); /* once for the get parent */
1659 if (IUnknown_Release(bufferParent
) > 0) {
1660 FIXME("(%p) Something's still holding the back buffer\n",This
);
1664 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1665 object
->backBuffer
= NULL
;
1667 if(object
->context
&& object
->context
[0])
1668 DestroyContext(This
, object
->context
[0]);
1669 if(object
->frontBuffer
) {
1670 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1671 IUnknown_Release(bufferParent
); /* once for the get parent */
1672 if (IUnknown_Release(bufferParent
) > 0) {
1673 FIXME("(%p) Something's still holding the front buffer\n",This
);
1676 HeapFree(GetProcessHeap(), 0, object
);
1680 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1681 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1682 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1683 TRACE("(%p)\n", This
);
1685 return This
->NumberOfSwapChains
;
1688 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1689 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1690 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1692 if(iSwapChain
< This
->NumberOfSwapChains
) {
1693 *pSwapChain
= This
->swapchains
[iSwapChain
];
1694 IWineD3DSwapChain_AddRef(*pSwapChain
);
1695 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1698 TRACE("Swapchain out of range\n");
1700 return WINED3DERR_INVALIDCALL
;
1705 * Vertex Declaration
1707 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1708 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
1709 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1710 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1711 HRESULT hr
= WINED3D_OK
;
1713 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1714 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1716 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1718 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1720 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration
*)object
);
1721 *ppVertexDeclaration
= NULL
;
1727 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1728 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1730 unsigned int idx
, idx2
;
1731 unsigned int offset
;
1732 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1733 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1734 BOOL has_blend_idx
= has_blend
&&
1735 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1736 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1737 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1738 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1739 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1740 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1741 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1743 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1744 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1746 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1747 WINED3DVERTEXELEMENT
*elements
= NULL
;
1750 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1751 if (has_blend_idx
) num_blends
--;
1753 /* Compute declaration size */
1754 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1755 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1757 /* convert the declaration */
1758 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1762 elements
[size
-1] = end_element
;
1765 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1766 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1767 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1769 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
) {
1770 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1771 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1774 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1775 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1777 elements
[idx
].UsageIndex
= 0;
1780 if (has_blend
&& (num_blends
> 0)) {
1781 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1782 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1784 switch(num_blends
) {
1785 case 1: elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
; break;
1786 case 2: elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
; break;
1787 case 3: elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
; break;
1788 case 4: elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
; break;
1790 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1793 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1794 elements
[idx
].UsageIndex
= 0;
1797 if (has_blend_idx
) {
1798 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1799 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1800 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1801 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1802 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1804 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1805 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1806 elements
[idx
].UsageIndex
= 0;
1810 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1811 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1812 elements
[idx
].UsageIndex
= 0;
1816 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1817 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1818 elements
[idx
].UsageIndex
= 0;
1822 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1823 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1824 elements
[idx
].UsageIndex
= 0;
1828 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1829 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1830 elements
[idx
].UsageIndex
= 1;
1833 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1834 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1835 switch (numcoords
) {
1836 case WINED3DFVF_TEXTUREFORMAT1
:
1837 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1839 case WINED3DFVF_TEXTUREFORMAT2
:
1840 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1842 case WINED3DFVF_TEXTUREFORMAT3
:
1843 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1845 case WINED3DFVF_TEXTUREFORMAT4
:
1846 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1849 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1850 elements
[idx
].UsageIndex
= idx2
;
1854 /* Now compute offsets, and initialize the rest of the fields */
1855 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1856 elements
[idx
].Stream
= 0;
1857 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1858 elements
[idx
].Offset
= offset
;
1859 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1862 *ppVertexElements
= elements
;
1866 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1867 WINED3DVERTEXELEMENT
* elements
= NULL
;
1868 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1872 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1873 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1875 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1876 HeapFree(GetProcessHeap(), 0, elements
);
1877 if (hr
!= S_OK
) return hr
;
1882 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1883 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1884 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1885 HRESULT hr
= WINED3D_OK
;
1887 if (!pFunction
) return WINED3DERR_INVALIDCALL
;
1889 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1890 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1892 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1894 if (vertex_declaration
) {
1895 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1898 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1900 if (WINED3D_OK
!= hr
) {
1901 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1902 IWineD3DVertexShader_Release(*ppVertexShader
);
1903 return WINED3DERR_INVALIDCALL
;
1905 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1910 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1911 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1912 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1913 HRESULT hr
= WINED3D_OK
;
1915 if (!pFunction
) return WINED3DERR_INVALIDCALL
;
1917 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1918 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1919 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1920 if (WINED3D_OK
== hr
) {
1921 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1922 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1924 WARN("(%p) : Failed to create pixel shader\n", This
);
1930 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
1931 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
1933 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1934 IWineD3DPaletteImpl
*object
;
1936 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1938 /* Create the new object */
1939 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1941 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1942 return E_OUTOFMEMORY
;
1945 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1947 object
->Flags
= Flags
;
1948 object
->parent
= Parent
;
1949 object
->wineD3DDevice
= This
;
1950 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1952 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1955 HeapFree( GetProcessHeap(), 0, object
);
1956 return E_OUTOFMEMORY
;
1959 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1961 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1965 *Palette
= (IWineD3DPalette
*) object
;
1970 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1974 HDC dcb
= NULL
, dcs
= NULL
;
1975 WINEDDCOLORKEY colorkey
;
1977 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1980 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1981 dcb
= CreateCompatibleDC(NULL
);
1983 SelectObject(dcb
, hbm
);
1987 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1988 * couldn't be loaded
1990 memset(&bm
, 0, sizeof(bm
));
1995 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1996 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1997 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1999 ERR("Wine logo requested, but failed to create surface\n");
2004 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
2005 if(FAILED(hr
)) goto out
;
2006 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
2007 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
2009 colorkey
.dwColorSpaceLowValue
= 0;
2010 colorkey
.dwColorSpaceHighValue
= 0;
2011 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
2013 /* Fill the surface with a white color to show that wined3d is there */
2014 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2027 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
2029 /* Under DirectX you can have texture stage operations even if no texture is
2030 bound, whereas opengl will only do texture operations when a valid texture is
2031 bound. We emulate this by creating dummy textures and binding them to each
2032 texture stage, but disable all stages by default. Hence if a stage is enabled
2033 then the default texture will kick in until replaced by a SetTexture call */
2036 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2037 /* The dummy texture does not have client storage backing */
2038 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2039 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2041 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2042 GLubyte white
= 255;
2044 /* Make appropriate texture active */
2045 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2046 checkGLcall("glActiveTextureARB");
2048 /* Generate an opengl texture name */
2049 glGenTextures(1, &This
->dummyTextureName
[i
]);
2050 checkGLcall("glGenTextures");
2051 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2053 /* Generate a dummy 2d texture (not using 1d because they cause many
2054 * DRI drivers fall back to sw) */
2055 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2056 checkGLcall("glBindTexture");
2058 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2059 checkGLcall("glTexImage2D");
2061 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2062 /* Reenable because if supported it is enabled by default */
2063 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2064 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2070 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain
) {
2071 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2072 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2077 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateSwapChain
);
2078 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2079 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2081 /* TODO: Test if OpenGL is compiled in and loaded */
2083 TRACE("(%p) : Creating stateblock\n", This
);
2084 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2085 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2087 (IWineD3DStateBlock
**)&This
->stateBlock
,
2089 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2090 WARN("Failed to create stateblock\n");
2093 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2094 This
->updateStateBlock
= This
->stateBlock
;
2095 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
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_CreateSwapChain(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 /* Initialize the current view state */
2191 This
->view_ident
= 1;
2192 This
->contexts
[0]->last_was_rhw
= 0;
2193 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2194 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2196 switch(wined3d_settings
.offscreen_rendering_mode
) {
2199 This
->offscreenBuffer
= GL_BACK
;
2202 case ORM_BACKBUFFER
:
2204 if(This
->activeContext
->aux_buffers
> 0) {
2205 TRACE("Using auxilliary buffer for offscreen rendering\n");
2206 This
->offscreenBuffer
= GL_AUX0
;
2208 TRACE("Using back buffer for offscreen rendering\n");
2209 This
->offscreenBuffer
= GL_BACK
;
2214 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2217 /* Clear the screen */
2218 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2219 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2222 This
->d3d_initialized
= TRUE
;
2224 if(wined3d_settings
.logo
) {
2225 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2227 This
->highest_dirty_ps_const
= 0;
2228 This
->highest_dirty_vs_const
= 0;
2232 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2233 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2234 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2235 This
->NumberOfSwapChains
= 0;
2236 if(This
->palettes
) {
2237 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2238 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2240 This
->NumberOfPalettes
= 0;
2242 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2244 if(This
->stateBlock
) {
2245 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2246 This
->stateBlock
= NULL
;
2248 if (This
->blit_priv
) {
2249 This
->blitter
->free_private(iface
);
2251 if (This
->fragment_priv
) {
2252 This
->frag_pipe
->free_private(iface
);
2254 if (This
->shader_priv
) {
2255 This
->shader_backend
->shader_free_private(iface
);
2260 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain
) {
2261 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2262 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2265 /* Setup the implicit swapchain */
2266 TRACE("Creating implicit swapchain\n");
2267 hr
=D3DCB_CreateSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2268 if (FAILED(hr
) || !swapchain
) {
2269 WARN("Failed to create implicit swapchain\n");
2273 This
->NumberOfSwapChains
= 1;
2274 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2275 if(!This
->swapchains
) {
2276 ERR("Out of memory!\n");
2279 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2283 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2287 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2288 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2291 TRACE("(%p)\n", This
);
2293 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2295 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2296 * it was created. Thus make sure a context is active for the glDelete* calls
2298 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2300 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2302 TRACE("Deleting high order patches\n");
2303 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2304 struct list
*e1
, *e2
;
2305 struct WineD3DRectPatch
*patch
;
2306 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2307 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2308 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2312 /* Delete the palette conversion shader if it is around */
2313 if(This
->paletteConversionShader
) {
2315 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2317 This
->paletteConversionShader
= 0;
2320 /* Delete the pbuffer context if there is any */
2321 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2323 /* Delete the mouse cursor texture */
2324 if(This
->cursorTexture
) {
2326 glDeleteTextures(1, &This
->cursorTexture
);
2328 This
->cursorTexture
= 0;
2331 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2332 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2334 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2335 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2338 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2339 * private data, it might contain opengl pointers
2341 if(This
->depth_blt_texture
) {
2342 glDeleteTextures(1, &This
->depth_blt_texture
);
2343 This
->depth_blt_texture
= 0;
2345 if (This
->depth_blt_rb
) {
2346 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2347 This
->depth_blt_rb
= 0;
2348 This
->depth_blt_rb_w
= 0;
2349 This
->depth_blt_rb_h
= 0;
2352 /* Release the update stateblock */
2353 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2354 if(This
->updateStateBlock
!= This
->stateBlock
)
2355 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2357 This
->updateStateBlock
= NULL
;
2359 { /* because were not doing proper internal refcounts releasing the primary state block
2360 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2361 to set this->stateBlock = NULL; first */
2362 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2363 This
->stateBlock
= NULL
;
2365 /* Release the stateblock */
2366 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2367 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2371 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2372 This
->blitter
->free_private(iface
);
2373 This
->frag_pipe
->free_private(iface
);
2374 This
->shader_backend
->shader_free_private(iface
);
2376 /* Release the buffers (with sanity checks)*/
2377 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2378 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2379 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2380 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2382 This
->stencilBufferTarget
= NULL
;
2384 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2385 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2386 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2388 TRACE("Setting rendertarget to NULL\n");
2389 This
->render_targets
[0] = NULL
;
2391 if (This
->auto_depth_stencil_buffer
) {
2392 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2393 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2395 This
->auto_depth_stencil_buffer
= NULL
;
2398 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2399 TRACE("Releasing the implicit swapchain %d\n", i
);
2400 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2401 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2405 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2406 This
->swapchains
= NULL
;
2407 This
->NumberOfSwapChains
= 0;
2409 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2410 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2411 This
->palettes
= NULL
;
2412 This
->NumberOfPalettes
= 0;
2414 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2415 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2416 This
->render_targets
= NULL
;
2417 This
->draw_buffers
= NULL
;
2419 This
->d3d_initialized
= FALSE
;
2423 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2424 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2427 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2428 TRACE("Releasing the implicit swapchain %d\n", i
);
2429 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2430 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2434 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2435 This
->swapchains
= NULL
;
2436 This
->NumberOfSwapChains
= 0;
2440 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2441 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2442 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2444 * There is no way to deactivate thread safety once it is enabled.
2446 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2447 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2449 /*For now just store the flag(needed in case of ddraw) */
2450 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2455 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
2456 const WINED3DDISPLAYMODE
* pMode
) {
2458 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2460 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2463 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2465 /* Resize the screen even without a window:
2466 * The app could have unset it with SetCooperativeLevel, but not called
2467 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2468 * but we don't have any hwnd
2471 memset(&devmode
, 0, sizeof(devmode
));
2472 devmode
.dmSize
= sizeof(devmode
);
2473 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2474 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2475 devmode
.dmPelsWidth
= pMode
->Width
;
2476 devmode
.dmPelsHeight
= pMode
->Height
;
2478 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2479 if (pMode
->RefreshRate
!= 0) {
2480 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2483 /* Only change the mode if necessary */
2484 if( (This
->ddraw_width
== pMode
->Width
) &&
2485 (This
->ddraw_height
== pMode
->Height
) &&
2486 (This
->ddraw_format
== pMode
->Format
) &&
2487 (pMode
->RefreshRate
== 0) ) {
2491 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2492 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2493 if(devmode
.dmDisplayFrequency
!= 0) {
2494 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2495 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2496 devmode
.dmDisplayFrequency
= 0;
2497 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2499 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2500 return WINED3DERR_NOTAVAILABLE
;
2504 /* Store the new values */
2505 This
->ddraw_width
= pMode
->Width
;
2506 This
->ddraw_height
= pMode
->Height
;
2507 This
->ddraw_format
= pMode
->Format
;
2509 /* And finally clip mouse to our screen */
2510 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2511 ClipCursor(&clip_rc
);
2516 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2517 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2518 *ppD3D
= This
->wineD3D
;
2519 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2520 IWineD3D_AddRef(*ppD3D
);
2524 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2525 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2527 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2528 (This
->adapter
->TextureRam
/(1024*1024)),
2529 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2530 /* return simulated texture memory left */
2531 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2535 * Get / Set Stream Source
2537 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2538 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2539 IWineD3DVertexBuffer
*oldSrc
;
2541 if (StreamNumber
>= MAX_STREAMS
) {
2542 WARN("Stream out of range %d\n", StreamNumber
);
2543 return WINED3DERR_INVALIDCALL
;
2544 } else if(OffsetInBytes
& 0x3) {
2545 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2546 return WINED3DERR_INVALIDCALL
;
2549 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2550 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2552 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
2554 if(oldSrc
== pStreamData
&&
2555 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2556 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2557 TRACE("Application is setting the old values over, nothing to do\n");
2561 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2563 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2564 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2567 /* Handle recording of state blocks */
2568 if (This
->isRecordingState
) {
2569 TRACE("Recording... not performing anything\n");
2570 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2571 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2575 /* Need to do a getParent and pass the references up */
2576 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2577 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2578 so for now, just count internally */
2579 if (pStreamData
!= NULL
) {
2580 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2581 InterlockedIncrement(&vbImpl
->bindCount
);
2582 IWineD3DVertexBuffer_AddRef(pStreamData
);
2584 if (oldSrc
!= NULL
) {
2585 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2586 IWineD3DVertexBuffer_Release(oldSrc
);
2589 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2594 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2595 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2597 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2598 This
->stateBlock
->streamSource
[StreamNumber
],
2599 This
->stateBlock
->streamOffset
[StreamNumber
],
2600 This
->stateBlock
->streamStride
[StreamNumber
]);
2602 if (StreamNumber
>= MAX_STREAMS
) {
2603 WARN("Stream out of range %d\n", StreamNumber
);
2604 return WINED3DERR_INVALIDCALL
;
2606 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2607 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2609 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2612 if (*pStream
!= NULL
) {
2613 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2618 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2619 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2620 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2621 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2623 /* Verify input at least in d3d9 this is invalid*/
2624 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2625 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2626 return WINED3DERR_INVALIDCALL
;
2628 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2629 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2630 return WINED3DERR_INVALIDCALL
;
2633 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2634 return WINED3DERR_INVALIDCALL
;
2637 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2638 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2640 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
2641 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2643 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2644 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2645 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2651 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2652 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2654 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2655 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2657 TRACE("(%p) : returning %d\n", This
, *Divider
);
2663 * Get / Set & Multiply Transform
2665 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2666 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2668 /* Most of this routine, comments included copied from ddraw tree initially: */
2669 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2671 /* Handle recording of state blocks */
2672 if (This
->isRecordingState
) {
2673 TRACE("Recording... not performing anything\n");
2674 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2675 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2680 * If the new matrix is the same as the current one,
2681 * we cut off any further processing. this seems to be a reasonable
2682 * optimization because as was noticed, some apps (warcraft3 for example)
2683 * tend towards setting the same matrix repeatedly for some reason.
2685 * From here on we assume that the new matrix is different, wherever it matters.
2687 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2688 TRACE("The app is setting the same matrix over again\n");
2691 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2695 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2696 where ViewMat = Camera space, WorldMat = world space.
2698 In OpenGL, camera and world space is combined into GL_MODELVIEW
2699 matrix. The Projection matrix stay projection matrix.
2702 /* Capture the times we can just ignore the change for now */
2703 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2704 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2705 /* Handled by the state manager */
2708 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2712 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2713 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2714 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2715 *pMatrix
= This
->stateBlock
->transforms
[State
];
2719 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2720 const WINED3DMATRIX
*mat
= NULL
;
2723 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2724 * below means it will be recorded in a state block change, but it
2725 * works regardless where it is recorded.
2726 * If this is found to be wrong, change to StateBlock.
2728 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2729 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2731 if (State
<= HIGHEST_TRANSFORMSTATE
)
2733 mat
= &This
->updateStateBlock
->transforms
[State
];
2735 FIXME("Unhandled transform state!!\n");
2738 multiply_matrix(&temp
, mat
, pMatrix
);
2740 /* Apply change via set transform - will reapply to eg. lights this way */
2741 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2747 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2748 you can reference any indexes you want as long as that number max are enabled at any
2749 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2750 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2751 but when recording, just build a chain pretty much of commands to be replayed. */
2753 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2755 PLIGHTINFOEL
*object
= NULL
;
2756 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2759 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2760 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2762 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2766 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2767 return WINED3DERR_INVALIDCALL
;
2770 switch(pLight
->Type
) {
2771 case WINED3DLIGHT_POINT
:
2772 case WINED3DLIGHT_SPOT
:
2773 case WINED3DLIGHT_PARALLELPOINT
:
2774 case WINED3DLIGHT_GLSPOT
:
2775 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2778 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2779 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2780 return WINED3DERR_INVALIDCALL
;
2784 case WINED3DLIGHT_DIRECTIONAL
:
2785 /* Ignores attenuation */
2789 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2790 return WINED3DERR_INVALIDCALL
;
2793 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2794 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2795 if(object
->OriginalIndex
== Index
) break;
2800 TRACE("Adding new light\n");
2801 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2803 ERR("Out of memory error when allocating a light\n");
2804 return E_OUTOFMEMORY
;
2806 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2807 object
->glIndex
= -1;
2808 object
->OriginalIndex
= Index
;
2809 object
->changed
= TRUE
;
2812 /* Initialize the object */
2813 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
,
2814 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2815 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2816 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2817 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2818 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2819 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2821 /* Save away the information */
2822 object
->OriginalParms
= *pLight
;
2824 switch (pLight
->Type
) {
2825 case WINED3DLIGHT_POINT
:
2827 object
->lightPosn
[0] = pLight
->Position
.x
;
2828 object
->lightPosn
[1] = pLight
->Position
.y
;
2829 object
->lightPosn
[2] = pLight
->Position
.z
;
2830 object
->lightPosn
[3] = 1.0f
;
2831 object
->cutoff
= 180.0f
;
2835 case WINED3DLIGHT_DIRECTIONAL
:
2837 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2838 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2839 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2840 object
->lightPosn
[3] = 0.0;
2841 object
->exponent
= 0.0f
;
2842 object
->cutoff
= 180.0f
;
2845 case WINED3DLIGHT_SPOT
:
2847 object
->lightPosn
[0] = pLight
->Position
.x
;
2848 object
->lightPosn
[1] = pLight
->Position
.y
;
2849 object
->lightPosn
[2] = pLight
->Position
.z
;
2850 object
->lightPosn
[3] = 1.0;
2853 object
->lightDirn
[0] = pLight
->Direction
.x
;
2854 object
->lightDirn
[1] = pLight
->Direction
.y
;
2855 object
->lightDirn
[2] = pLight
->Direction
.z
;
2856 object
->lightDirn
[3] = 1.0;
2859 * opengl-ish and d3d-ish spot lights use too different models for the
2860 * light "intensity" as a function of the angle towards the main light direction,
2861 * so we only can approximate very roughly.
2862 * however spot lights are rather rarely used in games (if ever used at all).
2863 * furthermore if still used, probably nobody pays attention to such details.
2865 if (pLight
->Falloff
== 0) {
2866 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2867 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2868 * will always be 1.0 for both of them, and we don't have to care for the
2869 * rest of the rather complex calculation
2871 object
->exponent
= 0;
2873 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2874 if (rho
< 0.0001) rho
= 0.0001f
;
2875 object
->exponent
= -0.3/log(cos(rho
/2));
2877 if (object
->exponent
> 128.0) {
2878 object
->exponent
= 128.0;
2880 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2886 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2889 /* Update the live definitions if the light is currently assigned a glIndex */
2890 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2891 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2896 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2897 PLIGHTINFOEL
*lightInfo
= NULL
;
2898 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2899 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2901 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2903 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2904 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2905 if(lightInfo
->OriginalIndex
== Index
) break;
2909 if (lightInfo
== NULL
) {
2910 TRACE("Light information requested but light not defined\n");
2911 return WINED3DERR_INVALIDCALL
;
2914 *pLight
= lightInfo
->OriginalParms
;
2919 * Get / Set Light Enable
2920 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2922 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2923 PLIGHTINFOEL
*lightInfo
= NULL
;
2924 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2925 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2927 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2929 /* Tests show true = 128...not clear why */
2930 Enable
= Enable
? 128: 0;
2932 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2933 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2934 if(lightInfo
->OriginalIndex
== Index
) break;
2937 TRACE("Found light: %p\n", lightInfo
);
2939 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2940 if (lightInfo
== NULL
) {
2942 TRACE("Light enabled requested but light not defined, so defining one!\n");
2943 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2945 /* Search for it again! Should be fairly quick as near head of list */
2946 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2947 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2948 if(lightInfo
->OriginalIndex
== Index
) break;
2951 if (lightInfo
== NULL
) {
2952 FIXME("Adding default lights has failed dismally\n");
2953 return WINED3DERR_INVALIDCALL
;
2957 lightInfo
->enabledChanged
= TRUE
;
2959 if(lightInfo
->glIndex
!= -1) {
2960 if(!This
->isRecordingState
) {
2961 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2964 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2965 lightInfo
->glIndex
= -1;
2967 TRACE("Light already disabled, nothing to do\n");
2969 lightInfo
->enabled
= FALSE
;
2971 lightInfo
->enabled
= TRUE
;
2972 if (lightInfo
->glIndex
!= -1) {
2974 TRACE("Nothing to do as light was enabled\n");
2977 /* Find a free gl light */
2978 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2979 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
2980 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
2981 lightInfo
->glIndex
= i
;
2985 if(lightInfo
->glIndex
== -1) {
2986 /* Our tests show that Windows returns D3D_OK in this situation, even with
2987 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2988 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2989 * as well for those lights.
2991 * TODO: Test how this affects rendering
2993 WARN("Too many concurrently active lights\n");
2997 /* i == lightInfo->glIndex */
2998 if(!This
->isRecordingState
) {
2999 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
3007 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
3009 PLIGHTINFOEL
*lightInfo
= NULL
;
3010 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3012 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3013 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3015 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3016 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3017 if(lightInfo
->OriginalIndex
== Index
) break;
3021 if (lightInfo
== NULL
) {
3022 TRACE("Light enabled state requested but light not defined\n");
3023 return WINED3DERR_INVALIDCALL
;
3025 /* true is 128 according to SetLightEnable */
3026 *pEnable
= lightInfo
->enabled
? 128 : 0;
3031 * Get / Set Clip Planes
3033 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3034 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3035 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3037 /* Validate Index */
3038 if (Index
>= GL_LIMITS(clipplanes
)) {
3039 TRACE("Application has requested clipplane this device doesn't support\n");
3040 return WINED3DERR_INVALIDCALL
;
3043 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
3045 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3046 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3047 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3048 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3049 TRACE("Application is setting old values over, nothing to do\n");
3053 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3054 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3055 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3056 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3058 /* Handle recording of state blocks */
3059 if (This
->isRecordingState
) {
3060 TRACE("Recording... not performing anything\n");
3064 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3069 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3070 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3071 TRACE("(%p) : for idx %d\n", This
, Index
);
3073 /* Validate Index */
3074 if (Index
>= GL_LIMITS(clipplanes
)) {
3075 TRACE("Application has requested clipplane this device doesn't support\n");
3076 return WINED3DERR_INVALIDCALL
;
3079 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3080 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3081 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3082 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3087 * Get / Set Clip Plane Status
3088 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3090 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3091 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3092 FIXME("(%p) : stub\n", This
);
3093 if (NULL
== pClipStatus
) {
3094 return WINED3DERR_INVALIDCALL
;
3096 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3097 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3101 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3102 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3103 FIXME("(%p) : stub\n", This
);
3104 if (NULL
== pClipStatus
) {
3105 return WINED3DERR_INVALIDCALL
;
3107 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3108 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3113 * Get / Set Material
3115 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3116 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3118 This
->updateStateBlock
->changed
.material
= TRUE
;
3119 This
->updateStateBlock
->material
= *pMaterial
;
3121 /* Handle recording of state blocks */
3122 if (This
->isRecordingState
) {
3123 TRACE("Recording... not performing anything\n");
3127 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3131 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3132 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3133 *pMaterial
= This
->updateStateBlock
->material
;
3134 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3135 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3136 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3137 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3138 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3139 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3140 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3141 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3142 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3150 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3151 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3152 IWineD3DIndexBuffer
*oldIdxs
;
3154 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3155 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3157 This
->updateStateBlock
->changed
.indices
= TRUE
;
3158 This
->updateStateBlock
->pIndexData
= pIndexData
;
3160 /* Handle recording of state blocks */
3161 if (This
->isRecordingState
) {
3162 TRACE("Recording... not performing anything\n");
3163 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3164 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3168 if(oldIdxs
!= pIndexData
) {
3169 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3170 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3171 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3176 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3177 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3179 *ppIndexData
= This
->stateBlock
->pIndexData
;
3181 /* up ref count on ppindexdata */
3183 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3184 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3186 TRACE("(%p) No index data set\n", This
);
3188 TRACE("Returning %p\n", *ppIndexData
);
3193 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3194 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3195 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3196 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3198 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3199 TRACE("Application is setting the old value over, nothing to do\n");
3203 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3205 if (This
->isRecordingState
) {
3206 TRACE("Recording... not performing anything\n");
3209 /* The base vertex index affects the stream sources */
3210 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3214 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3215 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3216 TRACE("(%p) : base_index %p\n", This
, base_index
);
3218 *base_index
= This
->stateBlock
->baseVertexIndex
;
3220 TRACE("Returning %u\n", *base_index
);
3226 * Get / Set Viewports
3228 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3229 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3231 TRACE("(%p)\n", This
);
3232 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3233 This
->updateStateBlock
->viewport
= *pViewport
;
3235 /* Handle recording of state blocks */
3236 if (This
->isRecordingState
) {
3237 TRACE("Recording... not performing anything\n");
3241 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3242 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3244 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3249 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3251 TRACE("(%p)\n", This
);
3252 *pViewport
= This
->stateBlock
->viewport
;
3257 * Get / Set Render States
3258 * TODO: Verify against dx9 definitions
3260 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3262 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3263 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3265 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3267 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
3268 This
->updateStateBlock
->renderState
[State
] = Value
;
3270 /* Handle recording of state blocks */
3271 if (This
->isRecordingState
) {
3272 TRACE("Recording... not performing anything\n");
3276 /* Compared here and not before the assignment to allow proper stateblock recording */
3277 if(Value
== oldValue
) {
3278 TRACE("Application is setting the old value over, nothing to do\n");
3280 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3286 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3287 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3288 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3289 *pValue
= This
->stateBlock
->renderState
[State
];
3294 * Get / Set Sampler States
3295 * TODO: Verify against dx9 definitions
3298 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3299 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3302 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3303 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3305 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3306 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3309 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3310 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3311 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3314 * SetSampler is designed to allow for more than the standard up to 8 textures
3315 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3316 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3318 * http://developer.nvidia.com/object/General_FAQ.html#t6
3320 * There are two new settings for GForce
3322 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3323 * and the texture one:
3324 * GL_MAX_TEXTURE_COORDS_ARB.
3325 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3328 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3329 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3330 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3332 /* Handle recording of state blocks */
3333 if (This
->isRecordingState
) {
3334 TRACE("Recording... not performing anything\n");
3338 if(oldValue
== Value
) {
3339 TRACE("Application is setting the old value over, nothing to do\n");
3343 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3348 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3349 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3351 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3352 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3354 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3355 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3358 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3359 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3360 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3362 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3363 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3368 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3369 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3371 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3372 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3373 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3376 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3378 if(This
->isRecordingState
) {
3379 TRACE("Recording... not performing anything\n");
3383 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3388 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3389 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3391 *pRect
= This
->updateStateBlock
->scissorRect
;
3392 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3396 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3397 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3398 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3400 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3402 This
->updateStateBlock
->vertexDecl
= pDecl
;
3403 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3405 if (This
->isRecordingState
) {
3406 TRACE("Recording... not performing anything\n");
3408 } else if(pDecl
== oldDecl
) {
3409 /* Checked after the assignment to allow proper stateblock recording */
3410 TRACE("Application is setting the old declaration over, nothing to do\n");
3414 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3418 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3419 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3421 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3423 *ppDecl
= This
->stateBlock
->vertexDecl
;
3424 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3428 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3429 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3430 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3432 This
->updateStateBlock
->vertexShader
= pShader
;
3433 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3435 if (This
->isRecordingState
) {
3436 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3437 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3438 TRACE("Recording... not performing anything\n");
3440 } else if(oldShader
== pShader
) {
3441 /* Checked here to allow proper stateblock recording */
3442 TRACE("App is setting the old shader over, nothing to do\n");
3446 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3447 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3448 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3450 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3455 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3456 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3458 if (NULL
== ppShader
) {
3459 return WINED3DERR_INVALIDCALL
;
3461 *ppShader
= This
->stateBlock
->vertexShader
;
3462 if( NULL
!= *ppShader
)
3463 IWineD3DVertexShader_AddRef(*ppShader
);
3465 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3469 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3470 IWineD3DDevice
*iface
,
3472 CONST BOOL
*srcData
,
3475 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3476 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3478 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3479 iface
, srcData
, start
, count
);
3481 if (srcData
== NULL
|| cnt
< 0)
3482 return WINED3DERR_INVALIDCALL
;
3484 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3485 for (i
= 0; i
< cnt
; i
++)
3486 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3488 for (i
= start
; i
< cnt
+ start
; ++i
) {
3489 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
3492 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3497 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3498 IWineD3DDevice
*iface
,
3503 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3504 int cnt
= min(count
, MAX_CONST_B
- start
);
3506 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3507 iface
, dstData
, start
, count
);
3509 if (dstData
== NULL
|| cnt
< 0)
3510 return WINED3DERR_INVALIDCALL
;
3512 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3516 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3517 IWineD3DDevice
*iface
,
3522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3523 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3525 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3526 iface
, srcData
, start
, count
);
3528 if (srcData
== NULL
|| cnt
< 0)
3529 return WINED3DERR_INVALIDCALL
;
3531 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3532 for (i
= 0; i
< cnt
; i
++)
3533 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3534 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3536 for (i
= start
; i
< cnt
+ start
; ++i
) {
3537 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
3540 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3545 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3546 IWineD3DDevice
*iface
,
3551 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3552 int cnt
= min(count
, MAX_CONST_I
- start
);
3554 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3555 iface
, dstData
, start
, count
);
3557 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3558 return WINED3DERR_INVALIDCALL
;
3560 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3564 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3565 IWineD3DDevice
*iface
,
3567 CONST
float *srcData
,
3570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3573 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3574 iface
, srcData
, start
, count
);
3576 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3577 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3578 return WINED3DERR_INVALIDCALL
;
3580 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3582 for (i
= 0; i
< count
; i
++)
3583 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3584 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3587 if (!This
->isRecordingState
)
3589 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
3590 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3593 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
3594 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
3599 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3600 IWineD3DDevice
*iface
,
3605 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3606 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3608 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3609 iface
, dstData
, start
, count
);
3611 if (dstData
== NULL
|| cnt
< 0)
3612 return WINED3DERR_INVALIDCALL
;
3614 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3618 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3620 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3621 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3625 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3626 int i
= This
->rev_tex_unit_map
[unit
];
3627 int j
= This
->texUnitMap
[stage
];
3629 This
->texUnitMap
[stage
] = unit
;
3630 if (i
!= -1 && i
!= stage
) {
3631 This
->texUnitMap
[i
] = -1;
3634 This
->rev_tex_unit_map
[unit
] = stage
;
3635 if (j
!= -1 && j
!= unit
) {
3636 This
->rev_tex_unit_map
[j
] = -1;
3640 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3643 This
->fixed_function_usage_map
= 0;
3644 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3645 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3646 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3647 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3648 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3649 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3650 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3651 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3652 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3654 if (color_op
== WINED3DTOP_DISABLE
) {
3655 /* Not used, and disable higher stages */
3659 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3660 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3661 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3662 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3663 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3664 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3665 This
->fixed_function_usage_map
|= (1 << i
);
3668 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3669 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3674 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3678 device_update_fixed_function_usage_map(This
);
3679 ffu_map
= This
->fixed_function_usage_map
;
3681 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3682 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3683 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3685 if (!(ffu_map
& 1)) continue;
3687 if (This
->texUnitMap
[i
] != i
) {
3688 device_map_stage(This
, i
, i
);
3689 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3690 markTextureStagesDirty(This
, i
);
3696 /* Now work out the mapping */
3698 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3700 if (!(ffu_map
& 1)) continue;
3702 if (This
->texUnitMap
[i
] != tex
) {
3703 device_map_stage(This
, i
, tex
);
3704 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3705 markTextureStagesDirty(This
, i
);
3712 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3713 const DWORD
*sampler_tokens
=
3714 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3717 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3718 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3719 device_map_stage(This
, i
, i
);
3720 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3721 if (i
< MAX_TEXTURES
) {
3722 markTextureStagesDirty(This
, i
);
3728 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
3729 const DWORD
*vshader_sampler_tokens
, int unit
)
3731 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3733 if (current_mapping
== -1) {
3734 /* Not currently used */
3738 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3739 /* Used by a fragment sampler */
3741 if (!pshader_sampler_tokens
) {
3742 /* No pixel shader, check fixed function */
3743 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3746 /* Pixel shader, check the shader's sampler map */
3747 return !pshader_sampler_tokens
[current_mapping
];
3750 /* Used by a vertex sampler */
3751 return !vshader_sampler_tokens
[current_mapping
];
3754 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3755 const DWORD
*vshader_sampler_tokens
=
3756 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3757 const DWORD
*pshader_sampler_tokens
= NULL
;
3758 int start
= GL_LIMITS(combined_samplers
) - 1;
3762 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3764 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3765 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3766 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3769 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3770 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3771 if (vshader_sampler_tokens
[i
]) {
3772 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3773 /* Already mapped somewhere */
3777 while (start
>= 0) {
3778 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3779 device_map_stage(This
, vsampler_idx
, start
);
3780 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3792 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3793 BOOL vs
= use_vs(This
->stateBlock
);
3794 BOOL ps
= use_ps(This
->stateBlock
);
3797 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3798 * that would be really messy and require shader recompilation
3799 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3800 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3803 device_map_psamplers(This
);
3805 device_map_fixed_function_samplers(This
);
3809 device_map_vsamplers(This
, ps
);
3813 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3814 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3815 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3816 This
->updateStateBlock
->pixelShader
= pShader
;
3817 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3819 /* Handle recording of state blocks */
3820 if (This
->isRecordingState
) {
3821 TRACE("Recording... not performing anything\n");
3824 if (This
->isRecordingState
) {
3825 TRACE("Recording... not performing anything\n");
3826 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3827 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3831 if(pShader
== oldShader
) {
3832 TRACE("App is setting the old pixel shader over, nothing to do\n");
3836 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3837 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3839 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3840 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3845 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3846 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3848 if (NULL
== ppShader
) {
3849 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3850 return WINED3DERR_INVALIDCALL
;
3853 *ppShader
= This
->stateBlock
->pixelShader
;
3854 if (NULL
!= *ppShader
) {
3855 IWineD3DPixelShader_AddRef(*ppShader
);
3857 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3861 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3862 IWineD3DDevice
*iface
,
3864 CONST BOOL
*srcData
,
3867 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3868 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3870 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3871 iface
, srcData
, start
, count
);
3873 if (srcData
== NULL
|| cnt
< 0)
3874 return WINED3DERR_INVALIDCALL
;
3876 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3877 for (i
= 0; i
< cnt
; i
++)
3878 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3880 for (i
= start
; i
< cnt
+ start
; ++i
) {
3881 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3884 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3889 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3890 IWineD3DDevice
*iface
,
3895 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3896 int cnt
= min(count
, MAX_CONST_B
- start
);
3898 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3899 iface
, dstData
, start
, count
);
3901 if (dstData
== NULL
|| cnt
< 0)
3902 return WINED3DERR_INVALIDCALL
;
3904 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3908 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3909 IWineD3DDevice
*iface
,
3914 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3915 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3917 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3918 iface
, srcData
, start
, count
);
3920 if (srcData
== NULL
|| cnt
< 0)
3921 return WINED3DERR_INVALIDCALL
;
3923 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3924 for (i
= 0; i
< cnt
; i
++)
3925 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3926 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3928 for (i
= start
; i
< cnt
+ start
; ++i
) {
3929 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3932 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3937 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3938 IWineD3DDevice
*iface
,
3943 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3944 int cnt
= min(count
, MAX_CONST_I
- start
);
3946 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3947 iface
, dstData
, start
, count
);
3949 if (dstData
== NULL
|| cnt
< 0)
3950 return WINED3DERR_INVALIDCALL
;
3952 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3956 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3957 IWineD3DDevice
*iface
,
3959 CONST
float *srcData
,
3962 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3965 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3966 iface
, srcData
, start
, count
);
3968 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3969 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3970 return WINED3DERR_INVALIDCALL
;
3972 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3974 for (i
= 0; i
< count
; i
++)
3975 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3976 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3979 if (!This
->isRecordingState
)
3981 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
3982 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3985 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3986 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3991 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3992 IWineD3DDevice
*iface
,
3997 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3998 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
4000 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4001 iface
, dstData
, start
, count
);
4003 if (dstData
== NULL
|| cnt
< 0)
4004 return WINED3DERR_INVALIDCALL
;
4006 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4010 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4011 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
4012 const WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
)
4014 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4016 DWORD DestFVF
= dest
->fvf
;
4018 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4022 if (lpStrideData
->u
.s
.normal
.lpData
) {
4023 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4026 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
4027 ERR("Source has no position mask\n");
4028 return WINED3DERR_INVALIDCALL
;
4031 /* We might access VBOs from this code, so hold the lock */
4034 if (dest
->resource
.allocatedMemory
== NULL
) {
4035 /* This may happen if we do direct locking into a vbo. Unlikely,
4036 * but theoretically possible(ddraw processvertices test)
4038 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4039 if(!dest
->resource
.allocatedMemory
) {
4041 ERR("Out of memory\n");
4042 return E_OUTOFMEMORY
;
4046 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4047 checkGLcall("glBindBufferARB");
4048 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4050 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4052 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4053 checkGLcall("glUnmapBufferARB");
4057 /* Get a pointer into the destination vbo(create one if none exists) and
4058 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4060 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
4061 dest
->Flags
|= VBFLAG_CREATEVBO
;
4062 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer
*) dest
);
4066 unsigned char extrabytes
= 0;
4067 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4068 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4069 * this may write 4 extra bytes beyond the area that should be written
4071 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4072 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4073 if(!dest_conv_addr
) {
4074 ERR("Out of memory\n");
4075 /* Continue without storing converted vertices */
4077 dest_conv
= dest_conv_addr
;
4081 * a) WINED3DRS_CLIPPING is enabled
4082 * b) WINED3DVOP_CLIP is passed
4084 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4085 static BOOL warned
= FALSE
;
4087 * The clipping code is not quite correct. Some things need
4088 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4089 * so disable clipping for now.
4090 * (The graphics in Half-Life are broken, and my processvertices
4091 * test crashes with IDirect3DDevice3)
4097 FIXME("Clipping is broken and disabled for now\n");
4099 } else doClip
= FALSE
;
4100 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4102 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4105 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4106 WINED3DTS_PROJECTION
,
4108 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4109 WINED3DTS_WORLDMATRIX(0),
4112 TRACE("View mat:\n");
4113 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
);
4114 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
);
4115 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
);
4116 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
);
4118 TRACE("Proj mat:\n");
4119 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
);
4120 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
);
4121 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
);
4122 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
);
4124 TRACE("World mat:\n");
4125 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
);
4126 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
);
4127 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
);
4128 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
);
4130 /* Get the viewport */
4131 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4132 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4133 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4135 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4136 multiply_matrix(&mat
,&proj_mat
,&mat
);
4138 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4140 for (i
= 0; i
< dwCount
; i
+= 1) {
4141 unsigned int tex_index
;
4143 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4144 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4145 /* The position first */
4147 (const float *)(lpStrideData
->u
.s
.position
.lpData
+ i
* lpStrideData
->u
.s
.position
.dwStride
);
4149 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4151 /* Multiplication with world, view and projection matrix */
4152 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
);
4153 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
);
4154 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
);
4155 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
);
4157 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4159 /* WARNING: The following things are taken from d3d7 and were not yet checked
4160 * against d3d8 or d3d9!
4163 /* Clipping conditions: From msdn
4165 * A vertex is clipped if it does not match the following requirements
4169 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4171 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4172 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4177 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4178 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4181 /* "Normal" viewport transformation (not clipped)
4182 * 1) The values are divided by rhw
4183 * 2) The y axis is negative, so multiply it with -1
4184 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4185 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4186 * 4) Multiply x with Width/2 and add Width/2
4187 * 5) The same for the height
4188 * 6) Add the viewpoint X and Y to the 2D coordinates and
4189 * The minimum Z value to z
4190 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4192 * Well, basically it's simply a linear transformation into viewport
4204 z
*= vp
.MaxZ
- vp
.MinZ
;
4206 x
+= vp
.Width
/ 2 + vp
.X
;
4207 y
+= vp
.Height
/ 2 + vp
.Y
;
4212 /* That vertex got clipped
4213 * Contrary to OpenGL it is not dropped completely, it just
4214 * undergoes a different calculation.
4216 TRACE("Vertex got clipped\n");
4223 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4224 * outside of the main vertex buffer memory. That needs some more
4229 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4232 ( (float *) dest_ptr
)[0] = x
;
4233 ( (float *) dest_ptr
)[1] = y
;
4234 ( (float *) dest_ptr
)[2] = z
;
4235 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4237 dest_ptr
+= 3 * sizeof(float);
4239 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4240 dest_ptr
+= sizeof(float);
4245 ( (float *) dest_conv
)[0] = x
* w
;
4246 ( (float *) dest_conv
)[1] = y
* w
;
4247 ( (float *) dest_conv
)[2] = z
* w
;
4248 ( (float *) dest_conv
)[3] = w
;
4250 dest_conv
+= 3 * sizeof(float);
4252 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4253 dest_conv
+= sizeof(float);
4257 if (DestFVF
& WINED3DFVF_PSIZE
) {
4258 dest_ptr
+= sizeof(DWORD
);
4259 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4261 if (DestFVF
& WINED3DFVF_NORMAL
) {
4262 const float *normal
=
4263 (const float *)(lpStrideData
->u
.s
.normal
.lpData
+ i
* lpStrideData
->u
.s
.normal
.dwStride
);
4264 /* AFAIK this should go into the lighting information */
4265 FIXME("Didn't expect the destination to have a normal\n");
4266 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4268 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4272 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4273 const DWORD
*color_d
=
4274 (const DWORD
*)(lpStrideData
->u
.s
.diffuse
.lpData
+ i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4276 static BOOL warned
= FALSE
;
4279 ERR("No diffuse color in source, but destination has one\n");
4283 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4284 dest_ptr
+= sizeof(DWORD
);
4287 *( (DWORD
*) dest_conv
) = 0xffffffff;
4288 dest_conv
+= sizeof(DWORD
);
4292 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4294 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4295 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4296 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4297 dest_conv
+= sizeof(DWORD
);
4302 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4303 /* What's the color value in the feedback buffer? */
4304 const DWORD
*color_s
=
4305 (const DWORD
*)(lpStrideData
->u
.s
.specular
.lpData
+ i
* lpStrideData
->u
.s
.specular
.dwStride
);
4307 static BOOL warned
= FALSE
;
4310 ERR("No specular color in source, but destination has one\n");
4314 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4315 dest_ptr
+= sizeof(DWORD
);
4318 *( (DWORD
*) dest_conv
) = 0xFF000000;
4319 dest_conv
+= sizeof(DWORD
);
4323 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4325 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4326 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4327 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4328 dest_conv
+= sizeof(DWORD
);
4333 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4334 const float *tex_coord
=
4335 (const float *)(lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
+
4336 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4338 ERR("No source texture, but destination requests one\n");
4339 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4340 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4343 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4345 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4352 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4353 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4354 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4355 dwCount
* get_flexible_vertex_size(DestFVF
),
4357 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4358 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4365 #undef copy_and_next
4367 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4368 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4369 WineDirect3DVertexStridedData strided
;
4370 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4371 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4374 ERR("Output vertex declaration not implemented yet\n");
4377 /* Need any context to write to the vbo. */
4378 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4380 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4381 * control the streamIsUP flag, thus restore it afterwards.
4383 This
->stateBlock
->streamIsUP
= FALSE
;
4384 memset(&strided
, 0, sizeof(strided
));
4385 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4386 This
->stateBlock
->streamIsUP
= streamWasUP
;
4388 if(vbo
|| SrcStartIndex
) {
4390 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4391 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4393 * Also get the start index in, but only loop over all elements if there's something to add at all.
4395 #define FIXSRC(type) \
4396 if(strided.u.s.type.VBO) { \
4397 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4398 strided.u.s.type.VBO = 0; \
4399 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4401 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4405 if(strided.u.s.type.lpData) { \
4406 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4409 FIXSRC(blendWeights
);
4410 FIXSRC(blendMatrixIndices
);
4415 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4416 FIXSRC(texCoords
[i
]);
4429 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4433 * Get / Set Texture Stage States
4434 * TODO: Verify against dx9 definitions
4436 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4437 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4438 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4440 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4442 if (Stage
>= MAX_TEXTURES
) {
4443 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4447 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4448 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4450 if (This
->isRecordingState
) {
4451 TRACE("Recording... not performing anything\n");
4455 /* Checked after the assignments to allow proper stateblock recording */
4456 if(oldValue
== Value
) {
4457 TRACE("App is setting the old value over, nothing to do\n");
4461 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4462 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4463 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4464 * Changes in other states are important on disabled stages too
4469 if(Type
== WINED3DTSS_COLOROP
) {
4472 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4473 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4474 * they have to be disabled
4476 * The current stage is dirtified below.
4478 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4479 TRACE("Additionally dirtifying stage %d\n", i
);
4480 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4482 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4483 TRACE("New lowest disabled: %d\n", Stage
);
4484 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4485 /* Previously disabled stage enabled. Stages above it may need enabling
4486 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4487 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4489 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4492 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4493 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4496 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4497 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4499 This
->stateBlock
->lowest_disabled_stage
= i
;
4500 TRACE("New lowest disabled: %d\n", i
);
4504 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4509 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4510 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4511 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4512 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4519 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4520 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4521 IWineD3DBaseTexture
*oldTexture
;
4523 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4525 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4526 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4529 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4530 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4531 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4534 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4536 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4537 if (pTexture
&& ((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
4539 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4540 return WINED3DERR_INVALIDCALL
;
4543 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4544 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4546 This
->updateStateBlock
->changed
.textures
|= 1 << Stage
;
4547 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4548 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4550 /* Handle recording of state blocks */
4551 if (This
->isRecordingState
) {
4552 TRACE("Recording... not performing anything\n");
4556 if(oldTexture
== pTexture
) {
4557 TRACE("App is setting the same texture again, nothing to do\n");
4561 /** NOTE: MSDN says that setTexture increases the reference count,
4562 * and that the application must set the texture back to null (or have a leaky application),
4563 * This means we should pass the refcount up to the parent
4564 *******************************/
4565 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4566 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4567 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4569 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4570 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4571 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4572 * so the COLOROP and ALPHAOP have to be dirtified.
4574 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4575 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4577 if(bindCount
== 1) {
4578 new->baseTexture
.sampler
= Stage
;
4580 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4584 if (NULL
!= oldTexture
) {
4585 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4586 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4588 IWineD3DBaseTexture_Release(oldTexture
);
4589 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4590 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4591 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4594 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4596 /* Have to do a search for the other sampler(s) where the texture is bound to
4597 * Shouldn't happen as long as apps bind a texture only to one stage
4599 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4600 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4601 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4602 old
->baseTexture
.sampler
= i
;
4609 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4614 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4615 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4617 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4619 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4620 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4623 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4624 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4625 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4628 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4630 IWineD3DBaseTexture_AddRef(*ppTexture
);
4632 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4640 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4641 IWineD3DSurface
**ppBackBuffer
) {
4642 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4643 IWineD3DSwapChain
*swapChain
;
4646 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4648 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4649 if (hr
== WINED3D_OK
) {
4650 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4651 IWineD3DSwapChain_Release(swapChain
);
4653 *ppBackBuffer
= NULL
;
4658 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4659 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4660 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4661 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4664 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4665 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4666 IWineD3DSwapChain
*swapChain
;
4669 if(iSwapChain
> 0) {
4670 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4671 if (hr
== WINED3D_OK
) {
4672 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4673 IWineD3DSwapChain_Release(swapChain
);
4675 FIXME("(%p) Error getting display mode\n", This
);
4678 /* Don't read the real display mode,
4679 but return the stored mode instead. X11 can't change the color
4680 depth, and some apps are pretty angry if they SetDisplayMode from
4681 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4683 Also don't relay to the swapchain because with ddraw it's possible
4684 that there isn't a swapchain at all */
4685 pMode
->Width
= This
->ddraw_width
;
4686 pMode
->Height
= This
->ddraw_height
;
4687 pMode
->Format
= This
->ddraw_format
;
4688 pMode
->RefreshRate
= 0;
4696 * Stateblock related functions
4699 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4700 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4701 IWineD3DStateBlockImpl
*object
;
4702 HRESULT temp_result
;
4705 TRACE("(%p)\n", This
);
4707 if (This
->isRecordingState
) {
4708 return WINED3DERR_INVALIDCALL
;
4711 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4712 if (NULL
== object
) {
4713 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4714 return E_OUTOFMEMORY
;
4716 TRACE("(%p) created object %p\n", This
, object
);
4717 object
->wineD3DDevice
= This
;
4718 /** FIXME: object->parent = parent; **/
4719 object
->parent
= NULL
;
4720 object
->blockType
= WINED3DSBT_RECORDED
;
4722 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4724 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4725 list_init(&object
->lightMap
[i
]);
4728 temp_result
= allocate_shader_constants(object
);
4729 if (WINED3D_OK
!= temp_result
)
4732 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4733 This
->updateStateBlock
= object
;
4734 This
->isRecordingState
= TRUE
;
4736 TRACE("(%p) recording stateblock %p\n",This
, object
);
4740 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4741 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4743 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4745 if (!This
->isRecordingState
) {
4746 WARN("(%p) not recording! returning error\n", This
);
4747 *ppStateBlock
= NULL
;
4748 return WINED3DERR_INVALIDCALL
;
4751 for (i
= 0; i
<= WINEHIGHEST_RENDER_STATE
>> 5; ++i
)
4753 DWORD map
= object
->changed
.renderState
[i
];
4754 for (j
= 0; map
; map
>>= 1, ++j
)
4756 if (!(map
& 1)) continue;
4758 object
->contained_render_states
[object
->num_contained_render_states
++] = (i
<< 5) | j
;
4762 for (i
= 0; i
<= HIGHEST_TRANSFORMSTATE
>> 5; ++i
)
4764 DWORD map
= object
->changed
.transform
[i
];
4765 for (j
= 0; map
; map
>>= 1, ++j
)
4767 if (!(map
& 1)) continue;
4769 object
->contained_transform_states
[object
->num_contained_transform_states
++] = (i
<< 5) | j
;
4772 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4773 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4774 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4775 object
->num_contained_vs_consts_f
++;
4778 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4779 if (object
->changed
.vertexShaderConstantsI
& (1 << i
))
4781 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4782 object
->num_contained_vs_consts_i
++;
4785 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4786 if (object
->changed
.vertexShaderConstantsB
& (1 << i
))
4788 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4789 object
->num_contained_vs_consts_b
++;
4792 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
)
4794 if (object
->changed
.pixelShaderConstantsF
[i
])
4796 object
->contained_ps_consts_f
[object
->num_contained_ps_consts_f
] = i
;
4797 ++object
->num_contained_ps_consts_f
;
4800 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4801 if (object
->changed
.pixelShaderConstantsI
& (1 << i
))
4803 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4804 object
->num_contained_ps_consts_i
++;
4807 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4808 if (object
->changed
.pixelShaderConstantsB
& (1 << i
))
4810 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4811 object
->num_contained_ps_consts_b
++;
4814 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4815 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4816 if(object
->changed
.textureState
[i
][j
]) {
4817 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4818 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4819 object
->num_contained_tss_states
++;
4823 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4824 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4825 if(object
->changed
.samplerState
[i
][j
]) {
4826 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4827 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4828 object
->num_contained_sampler_states
++;
4833 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4834 This
->isRecordingState
= FALSE
;
4835 This
->updateStateBlock
= This
->stateBlock
;
4836 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4837 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4838 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4843 * Scene related functions
4845 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4846 /* At the moment we have no need for any functionality at the beginning
4848 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4849 TRACE("(%p)\n", This
);
4852 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4853 return WINED3DERR_INVALIDCALL
;
4855 This
->inScene
= TRUE
;
4859 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4860 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4861 TRACE("(%p)\n", This
);
4863 if(!This
->inScene
) {
4864 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4865 return WINED3DERR_INVALIDCALL
;
4868 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4869 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4871 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4875 This
->inScene
= FALSE
;
4879 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4880 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4881 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4882 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4883 IWineD3DSwapChain
*swapChain
= NULL
;
4885 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4887 TRACE("(%p) Presenting the frame\n", This
);
4889 for(i
= 0 ; i
< swapchains
; i
++) {
4891 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4892 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4893 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4894 IWineD3DSwapChain_Release(swapChain
);
4900 /* Not called from the VTable (internal subroutine) */
4901 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4902 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4903 float Z
, DWORD Stencil
) {
4904 GLbitfield glMask
= 0;
4906 WINED3DRECT curRect
;
4908 const WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4909 UINT drawable_width
, drawable_height
;
4910 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4911 IWineD3DSwapChainImpl
*swapchain
= NULL
;
4913 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4914 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4915 * for the cleared parts, and the untouched parts.
4917 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4918 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4919 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4920 * checking all this if the dest surface is in the drawable anyway.
4922 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4924 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4925 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
4926 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4929 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4930 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4931 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
4932 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
4933 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4936 if(Count
> 0 && pRects
&& (
4937 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4938 pRects
[0].x2
< target
->currentDesc
.Width
||
4939 pRects
[0].y2
< target
->currentDesc
.Height
)) {
4940 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4947 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
4949 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
4952 /* Only set the values up once, as they are not changing */
4953 if (Flags
& WINED3DCLEAR_STENCIL
) {
4954 glClearStencil(Stencil
);
4955 checkGLcall("glClearStencil");
4956 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4957 glStencilMask(0xFFFFFFFF);
4960 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4961 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4962 glDepthMask(GL_TRUE
);
4964 checkGLcall("glClearDepth");
4965 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4966 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4968 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
4969 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
4970 surface_load_ds_location(This
->stencilBufferTarget
, location
);
4972 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4973 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4974 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
4975 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
4976 surface_load_ds_location(This
->stencilBufferTarget
, location
);
4978 else if (Count
> 0 && pRects
&& (
4979 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4980 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
4981 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
4982 surface_load_ds_location(This
->stencilBufferTarget
, location
);
4986 if (Flags
& WINED3DCLEAR_TARGET
) {
4987 TRACE("Clearing screen with glClear to color %x\n", Color
);
4988 glClearColor(D3DCOLOR_R(Color
),
4992 checkGLcall("glClearColor");
4994 /* Clear ALL colors! */
4995 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4996 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4999 vp_rect
.left
= vp
->X
;
5000 vp_rect
.top
= vp
->Y
;
5001 vp_rect
.right
= vp
->X
+ vp
->Width
;
5002 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5003 if (!(Count
> 0 && pRects
)) {
5004 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5005 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5007 if(This
->render_offscreen
) {
5008 glScissor(vp_rect
.left
, vp_rect
.top
,
5009 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5011 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5012 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5014 checkGLcall("glScissor");
5016 checkGLcall("glClear");
5018 /* Now process each rect in turn */
5019 for (i
= 0; i
< Count
; i
++) {
5020 /* Note gl uses lower left, width/height */
5021 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
5022 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5023 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5025 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5026 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5027 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5028 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5030 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5031 * The rectangle is not cleared, no error is returned, but further rectanlges are
5032 * still cleared if they are valid
5034 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5035 TRACE("Rectangle with negative dimensions, ignoring\n");
5039 if(This
->render_offscreen
) {
5040 glScissor(curRect
.x1
, curRect
.y1
,
5041 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5043 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5044 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5046 checkGLcall("glScissor");
5049 checkGLcall("glClear");
5053 /* Restore the old values (why..?) */
5054 if (Flags
& WINED3DCLEAR_STENCIL
) {
5055 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5057 if (Flags
& WINED3DCLEAR_TARGET
) {
5058 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5059 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5060 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5061 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5062 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5064 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5065 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5067 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5069 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5070 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5071 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5072 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5077 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
5078 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
5081 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5087 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5088 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5089 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5090 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5092 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5093 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5095 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5096 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5097 /* TODO: What about depth stencil buffers without stencil bits? */
5098 return WINED3DERR_INVALIDCALL
;
5101 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5107 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
5108 UINT PrimitiveCount
) {
5110 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5112 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
5113 debug_d3dprimitivetype(PrimitiveType
),
5114 StartVertex
, PrimitiveCount
);
5116 if(!This
->stateBlock
->vertexDecl
) {
5117 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5118 return WINED3DERR_INVALIDCALL
;
5121 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5122 if(This
->stateBlock
->streamIsUP
) {
5123 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5124 This
->stateBlock
->streamIsUP
= FALSE
;
5127 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5128 This
->stateBlock
->loadBaseVertexIndex
= 0;
5129 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5131 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5132 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
5133 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5137 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5138 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5139 WINED3DPRIMITIVETYPE PrimitiveType
,
5140 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
5142 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5144 IWineD3DIndexBuffer
*pIB
;
5145 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
5148 pIB
= This
->stateBlock
->pIndexData
;
5150 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5151 * without an index buffer set. (The first time at least...)
5152 * D3D8 simply dies, but I doubt it can do much harm to return
5153 * D3DERR_INVALIDCALL there as well. */
5154 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5155 return WINED3DERR_INVALIDCALL
;
5158 if(!This
->stateBlock
->vertexDecl
) {
5159 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5160 return WINED3DERR_INVALIDCALL
;
5163 if(This
->stateBlock
->streamIsUP
) {
5164 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5165 This
->stateBlock
->streamIsUP
= FALSE
;
5167 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5169 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5170 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5171 minIndex
, NumVertices
, startIndex
, primCount
);
5173 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5174 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5180 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5181 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5182 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5185 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5186 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5191 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5192 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5193 UINT VertexStreamZeroStride
) {
5194 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5195 IWineD3DVertexBuffer
*vb
;
5197 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5198 debug_d3dprimitivetype(PrimitiveType
),
5199 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5201 if(!This
->stateBlock
->vertexDecl
) {
5202 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5203 return WINED3DERR_INVALIDCALL
;
5206 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5207 vb
= This
->stateBlock
->streamSource
[0];
5208 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5209 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5210 This
->stateBlock
->streamOffset
[0] = 0;
5211 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5212 This
->stateBlock
->streamIsUP
= TRUE
;
5213 This
->stateBlock
->loadBaseVertexIndex
= 0;
5215 /* TODO: Only mark dirty if drawing from a different UP address */
5216 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5218 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5219 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5221 /* MSDN specifies stream zero settings must be set to NULL */
5222 This
->stateBlock
->streamStride
[0] = 0;
5223 This
->stateBlock
->streamSource
[0] = NULL
;
5225 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5226 * the new stream sources or use UP drawing again
5231 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5232 UINT MinVertexIndex
, UINT NumVertices
,
5233 UINT PrimitiveCount
, CONST
void* pIndexData
,
5234 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5235 UINT VertexStreamZeroStride
) {
5237 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5238 IWineD3DVertexBuffer
*vb
;
5239 IWineD3DIndexBuffer
*ib
;
5241 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5242 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5243 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5244 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5246 if(!This
->stateBlock
->vertexDecl
) {
5247 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5248 return WINED3DERR_INVALIDCALL
;
5251 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5257 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5258 vb
= This
->stateBlock
->streamSource
[0];
5259 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5260 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5261 This
->stateBlock
->streamIsUP
= TRUE
;
5262 This
->stateBlock
->streamOffset
[0] = 0;
5263 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5265 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5266 This
->stateBlock
->baseVertexIndex
= 0;
5267 This
->stateBlock
->loadBaseVertexIndex
= 0;
5268 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5269 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5270 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5272 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5274 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5275 This
->stateBlock
->streamSource
[0] = NULL
;
5276 This
->stateBlock
->streamStride
[0] = 0;
5277 ib
= This
->stateBlock
->pIndexData
;
5279 IWineD3DIndexBuffer_Release(ib
);
5280 This
->stateBlock
->pIndexData
= NULL
;
5282 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5283 * SetStreamSource to specify a vertex buffer
5289 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
5290 WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
,
5291 const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
5293 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5295 /* Mark the state dirty until we have nicer tracking
5296 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5299 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5300 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5301 This
->stateBlock
->baseVertexIndex
= 0;
5302 This
->up_strided
= DrawPrimStrideData
;
5303 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5304 This
->up_strided
= NULL
;
5308 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
5309 WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
,
5310 const WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, const void *pIndexData
,
5311 WINED3DFORMAT IndexDataFormat
)
5313 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5314 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5316 /* Mark the state dirty until we have nicer tracking
5317 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5320 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5321 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5322 This
->stateBlock
->streamIsUP
= TRUE
;
5323 This
->stateBlock
->baseVertexIndex
= 0;
5324 This
->up_strided
= DrawPrimStrideData
;
5325 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5326 This
->up_strided
= NULL
;
5330 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5331 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5332 * not callable by the app directly no parameter validation checks are needed here.
5334 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5335 WINED3DLOCKED_BOX src
;
5336 WINED3DLOCKED_BOX dst
;
5338 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5340 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5341 * dirtification to improve loading performance.
5343 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5344 if(FAILED(hr
)) return hr
;
5345 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5347 IWineD3DVolume_UnlockBox(pSourceVolume
);
5351 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5353 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5355 IWineD3DVolume_UnlockBox(pSourceVolume
);
5357 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5362 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5363 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5364 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5365 HRESULT hr
= WINED3D_OK
;
5366 WINED3DRESOURCETYPE sourceType
;
5367 WINED3DRESOURCETYPE destinationType
;
5370 /* TODO: think about moving the code into IWineD3DBaseTexture */
5372 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5374 /* verify that the source and destination textures aren't NULL */
5375 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5376 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5377 This
, pSourceTexture
, pDestinationTexture
);
5378 hr
= WINED3DERR_INVALIDCALL
;
5381 if (pSourceTexture
== pDestinationTexture
) {
5382 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5383 This
, pSourceTexture
, pDestinationTexture
);
5384 hr
= WINED3DERR_INVALIDCALL
;
5386 /* Verify that the source and destination textures are the same type */
5387 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5388 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5390 if (sourceType
!= destinationType
) {
5391 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5393 hr
= WINED3DERR_INVALIDCALL
;
5396 /* check that both textures have the identical numbers of levels */
5397 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5398 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5399 hr
= WINED3DERR_INVALIDCALL
;
5402 if (WINED3D_OK
== hr
) {
5404 /* Make sure that the destination texture is loaded */
5405 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5407 /* Update every surface level of the texture */
5408 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5410 switch (sourceType
) {
5411 case WINED3DRTYPE_TEXTURE
:
5413 IWineD3DSurface
*srcSurface
;
5414 IWineD3DSurface
*destSurface
;
5416 for (i
= 0 ; i
< levels
; ++i
) {
5417 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5418 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5419 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5420 IWineD3DSurface_Release(srcSurface
);
5421 IWineD3DSurface_Release(destSurface
);
5422 if (WINED3D_OK
!= hr
) {
5423 WARN("(%p) : Call to update surface failed\n", This
);
5429 case WINED3DRTYPE_CUBETEXTURE
:
5431 IWineD3DSurface
*srcSurface
;
5432 IWineD3DSurface
*destSurface
;
5433 WINED3DCUBEMAP_FACES faceType
;
5435 for (i
= 0 ; i
< levels
; ++i
) {
5436 /* Update each cube face */
5437 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5438 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5439 if (WINED3D_OK
!= hr
) {
5440 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5442 TRACE("Got srcSurface %p\n", srcSurface
);
5444 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5445 if (WINED3D_OK
!= hr
) {
5446 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5448 TRACE("Got desrSurface %p\n", destSurface
);
5450 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5451 IWineD3DSurface_Release(srcSurface
);
5452 IWineD3DSurface_Release(destSurface
);
5453 if (WINED3D_OK
!= hr
) {
5454 WARN("(%p) : Call to update surface failed\n", This
);
5462 case WINED3DRTYPE_VOLUMETEXTURE
:
5464 IWineD3DVolume
*srcVolume
= NULL
;
5465 IWineD3DVolume
*destVolume
= NULL
;
5467 for (i
= 0 ; i
< levels
; ++i
) {
5468 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5469 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5470 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5471 IWineD3DVolume_Release(srcVolume
);
5472 IWineD3DVolume_Release(destVolume
);
5473 if (WINED3D_OK
!= hr
) {
5474 WARN("(%p) : Call to update volume failed\n", This
);
5482 FIXME("(%p) : Unsupported source and destination type\n", This
);
5483 hr
= WINED3DERR_INVALIDCALL
;
5490 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5491 IWineD3DSwapChain
*swapChain
;
5493 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5494 if(hr
== WINED3D_OK
) {
5495 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5496 IWineD3DSwapChain_Release(swapChain
);
5501 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5502 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5503 IWineD3DBaseTextureImpl
*texture
;
5504 const struct GlPixelFormatDesc
*gl_info
;
5507 TRACE("(%p) : %p\n", This
, pNumPasses
);
5509 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5510 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
5511 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5512 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5514 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
5515 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5516 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5519 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
5520 if(!texture
) continue;
5521 getFormatDescEntry(texture
->resource
.format
, &GLINFO_LOCATION
, &gl_info
);
5522 if(gl_info
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
5524 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
5525 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
5528 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
5529 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
5532 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
5533 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
5534 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
5539 /* return a sensible default */
5542 TRACE("returning D3D_OK\n");
5546 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5550 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5551 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5552 if (texture
&& (texture
->resource
.format
== WINED3DFMT_P8
|| texture
->resource
.format
== WINED3DFMT_A8P8
)) {
5553 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5558 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5559 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5562 PALETTEENTRY
**palettes
;
5564 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5566 if (PaletteNumber
>= MAX_PALETTES
) {
5567 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5568 return WINED3DERR_INVALIDCALL
;
5571 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5572 NewSize
= This
->NumberOfPalettes
;
5575 } while(PaletteNumber
>= NewSize
);
5576 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5578 ERR("Out of memory!\n");
5579 return E_OUTOFMEMORY
;
5581 This
->palettes
= palettes
;
5582 This
->NumberOfPalettes
= NewSize
;
5585 if (!This
->palettes
[PaletteNumber
]) {
5586 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5587 if (!This
->palettes
[PaletteNumber
]) {
5588 ERR("Out of memory!\n");
5589 return E_OUTOFMEMORY
;
5593 for (j
= 0; j
< 256; ++j
) {
5594 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5595 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5596 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5597 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5599 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5600 TRACE("(%p) : returning\n", This
);
5604 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5605 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5607 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5608 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5609 /* What happens in such situation isn't documented; Native seems to silently abort
5610 on such conditions. Return Invalid Call. */
5611 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5612 return WINED3DERR_INVALIDCALL
;
5614 for (j
= 0; j
< 256; ++j
) {
5615 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5616 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5617 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5618 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5620 TRACE("(%p) : returning\n", This
);
5624 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5625 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5626 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5627 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5628 (tested with reference rasterizer). Return Invalid Call. */
5629 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5630 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5631 return WINED3DERR_INVALIDCALL
;
5633 /*TODO: stateblocks */
5634 if (This
->currentPalette
!= PaletteNumber
) {
5635 This
->currentPalette
= PaletteNumber
;
5636 dirtify_p8_texture_samplers(This
);
5638 TRACE("(%p) : returning\n", This
);
5642 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5643 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5644 if (PaletteNumber
== NULL
) {
5645 WARN("(%p) : returning Invalid Call\n", This
);
5646 return WINED3DERR_INVALIDCALL
;
5648 /*TODO: stateblocks */
5649 *PaletteNumber
= This
->currentPalette
;
5650 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5654 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5655 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5659 FIXME("(%p) : stub\n", This
);
5663 This
->softwareVertexProcessing
= bSoftware
;
5668 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5669 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5673 FIXME("(%p) : stub\n", This
);
5676 return This
->softwareVertexProcessing
;
5680 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5681 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5682 IWineD3DSwapChain
*swapChain
;
5685 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5687 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5688 if(hr
== WINED3D_OK
){
5689 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5690 IWineD3DSwapChain_Release(swapChain
);
5692 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5698 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5699 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5701 if(nSegments
!= 0.0f
) {
5704 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5711 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5712 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5716 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5722 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5723 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5724 /** TODO: remove casts to IWineD3DSurfaceImpl
5725 * NOTE: move code to surface to accomplish this
5726 ****************************************/
5727 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5728 int srcWidth
, srcHeight
;
5729 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5730 WINED3DFORMAT destFormat
, srcFormat
;
5732 int srcLeft
, destLeft
, destTop
;
5733 WINED3DPOOL srcPool
, destPool
;
5735 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5736 glDescriptor
*glDescription
= NULL
;
5740 CONVERT_TYPES convert
= NO_CONVERSION
;
5742 WINED3DSURFACE_DESC winedesc
;
5744 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5745 memset(&winedesc
, 0, sizeof(winedesc
));
5746 winedesc
.Width
= &srcSurfaceWidth
;
5747 winedesc
.Height
= &srcSurfaceHeight
;
5748 winedesc
.Pool
= &srcPool
;
5749 winedesc
.Format
= &srcFormat
;
5751 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5753 winedesc
.Width
= &destSurfaceWidth
;
5754 winedesc
.Height
= &destSurfaceHeight
;
5755 winedesc
.Pool
= &destPool
;
5756 winedesc
.Format
= &destFormat
;
5757 winedesc
.Size
= &destSize
;
5759 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5761 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5762 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5763 return WINED3DERR_INVALIDCALL
;
5766 /* This call loads the opengl surface directly, instead of copying the surface to the
5767 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5768 * copy in sysmem and use regular surface loading.
5770 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5771 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5772 if(convert
!= NO_CONVERSION
) {
5773 return IWineD3DSurface_BltFast(pDestinationSurface
,
5774 pDestPoint
? pDestPoint
->x
: 0,
5775 pDestPoint
? pDestPoint
->y
: 0,
5776 pSourceSurface
, pSourceRect
, 0);
5779 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5780 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5781 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5783 /* Get the update surface description */
5784 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5787 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5790 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5791 checkGLcall("glActiveTextureARB");
5794 /* Make sure the surface is loaded and up to date */
5795 IWineD3DSurface_PreLoad(pDestinationSurface
);
5796 IWineD3DSurface_BindTexture(pDestinationSurface
);
5798 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5800 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5801 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5802 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5803 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5804 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5805 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5808 /* This function doesn't support compressed textures
5809 the pitch is just bytesPerPixel * width */
5810 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5811 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5812 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5813 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5815 /* TODO DXT formats */
5817 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5818 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5820 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5821 This
, glDescription
->level
, destLeft
, destTop
, srcWidth
, srcHeight
, glDescription
->glFormat
,
5822 glDescription
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5825 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5827 /* need to lock the surface to get the data */
5828 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5833 /* TODO: Cube and volume support */
5835 /* not a whole row so we have to do it a line at a time */
5838 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5839 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5841 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5843 glTexSubImage2D(glDescription
->target
5844 ,glDescription
->level
5849 ,glDescription
->glFormat
5850 ,glDescription
->glType
5851 ,data
/* could be quicker using */
5856 } else { /* Full width, so just write out the whole texture */
5857 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5859 if (WINED3DFMT_DXT1
== destFormat
||
5860 WINED3DFMT_DXT2
== destFormat
||
5861 WINED3DFMT_DXT3
== destFormat
||
5862 WINED3DFMT_DXT4
== destFormat
||
5863 WINED3DFMT_DXT5
== destFormat
) {
5864 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5865 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5866 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5867 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5868 } if (destFormat
!= srcFormat
) {
5869 FIXME("Updating mixed format compressed texture is not curretly support\n");
5871 GL_EXTCALL(glCompressedTexImage2DARB(glDescription
->target
, glDescription
->level
,
5872 glDescription
->glFormatInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5875 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5880 glTexSubImage2D(glDescription
->target
, glDescription
->level
, destLeft
, destTop
,
5881 srcWidth
, srcHeight
, glDescription
->glFormat
, glDescription
->glType
, data
);
5884 checkGLcall("glTexSubImage2D");
5888 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5889 sampler
= This
->rev_tex_unit_map
[0];
5890 if (sampler
!= -1) {
5891 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5897 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5898 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5899 struct WineD3DRectPatch
*patch
;
5903 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5905 if(!(Handle
|| pRectPatchInfo
)) {
5906 /* TODO: Write a test for the return value, thus the FIXME */
5907 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5908 return WINED3DERR_INVALIDCALL
;
5912 i
= PATCHMAP_HASHFUNC(Handle
);
5914 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5915 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5916 if(patch
->Handle
== Handle
) {
5923 TRACE("Patch does not exist. Creating a new one\n");
5924 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5925 patch
->Handle
= Handle
;
5926 list_add_head(&This
->patches
[i
], &patch
->entry
);
5928 TRACE("Found existing patch %p\n", patch
);
5931 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5932 * attributes we have to tesselate, read back, and draw. This needs a patch
5933 * management structure instance. Create one.
5935 * A possible improvement is to check if a vertex shader is used, and if not directly
5938 FIXME("Drawing an uncached patch. This is slow\n");
5939 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5942 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5943 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5944 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5946 TRACE("Tesselation density or patch info changed, retesselating\n");
5948 if(pRectPatchInfo
) {
5949 patch
->RectPatchInfo
= *pRectPatchInfo
;
5951 patch
->numSegs
[0] = pNumSegs
[0];
5952 patch
->numSegs
[1] = pNumSegs
[1];
5953 patch
->numSegs
[2] = pNumSegs
[2];
5954 patch
->numSegs
[3] = pNumSegs
[3];
5956 hr
= tesselate_rectpatch(This
, patch
);
5958 WARN("Patch tesselation failed\n");
5960 /* Do not release the handle to store the params of the patch */
5962 HeapFree(GetProcessHeap(), 0, patch
);
5968 This
->currentPatch
= patch
;
5969 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
5970 This
->currentPatch
= NULL
;
5972 /* Destroy uncached patches */
5974 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5975 HeapFree(GetProcessHeap(), 0, patch
);
5980 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5981 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5982 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5983 FIXME("(%p) : Stub\n", This
);
5987 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5988 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5990 struct WineD3DRectPatch
*patch
;
5992 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5994 i
= PATCHMAP_HASHFUNC(Handle
);
5995 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5996 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5997 if(patch
->Handle
== Handle
) {
5998 TRACE("Deleting patch %p\n", patch
);
5999 list_remove(&patch
->entry
);
6000 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6001 HeapFree(GetProcessHeap(), 0, patch
);
6006 /* TODO: Write a test for the return value */
6007 FIXME("Attempt to destroy nonexistent patch\n");
6008 return WINED3DERR_INVALIDCALL
;
6011 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6013 IWineD3DSwapChain
*swapchain
;
6015 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6016 if (SUCCEEDED(hr
)) {
6017 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6024 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
6025 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6026 IWineD3DSwapChain
*swapchain
;
6028 swapchain
= get_swapchain(surface
);
6032 TRACE("Surface %p is onscreen\n", surface
);
6034 ActivateContext(This
, surface
, CTXUSAGE_RESOURCELOAD
);
6036 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6037 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6038 glDrawBuffer(buffer
);
6039 checkGLcall("glDrawBuffer()");
6041 TRACE("Surface %p is offscreen\n", surface
);
6043 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6045 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6046 context_attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6047 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6048 checkGLcall("glFramebufferRenderbufferEXT");
6052 glEnable(GL_SCISSOR_TEST
);
6054 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6056 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6057 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6059 checkGLcall("glScissor");
6060 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
6062 glDisable(GL_SCISSOR_TEST
);
6064 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6066 glDisable(GL_BLEND
);
6067 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
6069 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6070 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6072 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
6073 glClear(GL_COLOR_BUFFER_BIT
);
6074 checkGLcall("glClear");
6076 if (This
->activeContext
->current_fbo
) {
6077 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6079 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6080 checkGLcall("glBindFramebuffer()");
6083 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6084 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6085 glDrawBuffer(GL_BACK
);
6086 checkGLcall("glDrawBuffer()");
6092 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6093 unsigned int r
, g
, b
, a
;
6096 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6097 destfmt
== WINED3DFMT_R8G8B8
)
6100 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6102 a
= (color
& 0xff000000) >> 24;
6103 r
= (color
& 0x00ff0000) >> 16;
6104 g
= (color
& 0x0000ff00) >> 8;
6105 b
= (color
& 0x000000ff) >> 0;
6109 case WINED3DFMT_R5G6B5
:
6110 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6117 TRACE("Returning %08x\n", ret
);
6120 case WINED3DFMT_X1R5G5B5
:
6121 case WINED3DFMT_A1R5G5B5
:
6130 TRACE("Returning %08x\n", ret
);
6134 TRACE("Returning %08x\n", a
);
6137 case WINED3DFMT_X4R4G4B4
:
6138 case WINED3DFMT_A4R4G4B4
:
6147 TRACE("Returning %08x\n", ret
);
6150 case WINED3DFMT_R3G3B2
:
6157 TRACE("Returning %08x\n", ret
);
6160 case WINED3DFMT_X8B8G8R8
:
6161 case WINED3DFMT_A8B8G8R8
:
6166 TRACE("Returning %08x\n", ret
);
6169 case WINED3DFMT_A2R10G10B10
:
6171 r
= (r
* 1024) / 256;
6172 g
= (g
* 1024) / 256;
6173 b
= (b
* 1024) / 256;
6178 TRACE("Returning %08x\n", ret
);
6181 case WINED3DFMT_A2B10G10R10
:
6183 r
= (r
* 1024) / 256;
6184 g
= (g
* 1024) / 256;
6185 b
= (b
* 1024) / 256;
6190 TRACE("Returning %08x\n", ret
);
6194 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6199 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6200 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6201 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6203 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6205 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6206 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6207 return WINED3DERR_INVALIDCALL
;
6210 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6211 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6214 /* Just forward this to the DirectDraw blitting engine */
6215 memset(&BltFx
, 0, sizeof(BltFx
));
6216 BltFx
.dwSize
= sizeof(BltFx
);
6217 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6218 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
6219 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6223 /* rendertarget and depth stencil functions */
6224 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6225 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6227 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6228 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6229 return WINED3DERR_INVALIDCALL
;
6232 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6233 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6234 /* Note inc ref on returned surface */
6235 if(*ppRenderTarget
!= NULL
)
6236 IWineD3DSurface_AddRef(*ppRenderTarget
);
6240 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6241 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6242 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6243 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6244 IWineD3DSwapChainImpl
*Swapchain
;
6247 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6249 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6250 if(hr
!= WINED3D_OK
) {
6251 ERR("Can't get the swapchain\n");
6255 /* Make sure to release the swapchain */
6256 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6258 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6259 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6260 return WINED3DERR_INVALIDCALL
;
6262 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6263 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6264 return WINED3DERR_INVALIDCALL
;
6267 if(Swapchain
->frontBuffer
!= Front
) {
6268 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6270 if(Swapchain
->frontBuffer
)
6271 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6272 Swapchain
->frontBuffer
= Front
;
6274 if(Swapchain
->frontBuffer
) {
6275 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6279 if(Back
&& !Swapchain
->backBuffer
) {
6280 /* We need memory for the back buffer array - only one back buffer this way */
6281 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6282 if(!Swapchain
->backBuffer
) {
6283 ERR("Out of memory\n");
6284 return E_OUTOFMEMORY
;
6288 if(Swapchain
->backBuffer
[0] != Back
) {
6289 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6291 /* What to do about the context here in the case of multithreading? Not sure.
6292 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6295 if(!Swapchain
->backBuffer
[0]) {
6296 /* GL was told to draw to the front buffer at creation,
6299 glDrawBuffer(GL_BACK
);
6300 checkGLcall("glDrawBuffer(GL_BACK)");
6301 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6302 Swapchain
->presentParms
.BackBufferCount
= 1;
6304 /* That makes problems - disable for now */
6305 /* glDrawBuffer(GL_FRONT); */
6306 checkGLcall("glDrawBuffer(GL_FRONT)");
6307 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6308 Swapchain
->presentParms
.BackBufferCount
= 0;
6312 if(Swapchain
->backBuffer
[0])
6313 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6314 Swapchain
->backBuffer
[0] = Back
;
6316 if(Swapchain
->backBuffer
[0]) {
6317 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6319 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6320 Swapchain
->backBuffer
= NULL
;
6328 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6329 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6330 *ppZStencilSurface
= This
->stencilBufferTarget
;
6331 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6333 if(*ppZStencilSurface
!= NULL
) {
6334 /* Note inc ref on returned surface */
6335 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6338 return WINED3DERR_NOTFOUND
;
6342 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6343 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
)
6345 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6346 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6347 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6349 POINT offset
= {0, 0};
6351 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6352 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6353 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6354 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6357 case WINED3DTEXF_LINEAR
:
6358 gl_filter
= GL_LINEAR
;
6362 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6363 case WINED3DTEXF_NONE
:
6364 case WINED3DTEXF_POINT
:
6365 gl_filter
= GL_NEAREST
;
6369 /* Attach src surface to src fbo */
6370 src_swapchain
= get_swapchain(src_surface
);
6371 if (src_swapchain
) {
6372 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6374 TRACE("Source surface %p is onscreen\n", src_surface
);
6375 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6376 /* Make sure the drawable is up to date. In the offscreen case
6377 * attach_surface_fbo() implicitly takes care of this. */
6378 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6380 if(buffer
== GL_FRONT
) {
6383 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
6384 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
6385 h
= windowsize
.bottom
- windowsize
.top
;
6386 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6387 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6388 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6390 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6391 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6395 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6396 glReadBuffer(buffer
);
6397 checkGLcall("glReadBuffer()");
6399 TRACE("Source surface %p is offscreen\n", src_surface
);
6401 context_bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->activeContext
->src_fbo
);
6402 context_attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6403 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6404 checkGLcall("glReadBuffer()");
6405 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6406 checkGLcall("glFramebufferRenderbufferEXT");
6410 /* Attach dst surface to dst fbo */
6411 dst_swapchain
= get_swapchain(dst_surface
);
6412 if (dst_swapchain
) {
6413 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6415 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6416 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6417 /* Make sure the drawable is up to date. In the offscreen case
6418 * attach_surface_fbo() implicitly takes care of this. */
6419 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6421 if(buffer
== GL_FRONT
) {
6424 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
6425 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
6426 h
= windowsize
.bottom
- windowsize
.top
;
6427 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6428 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6429 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6431 /* Screen coords = window coords, surface height = window height */
6432 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6433 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6437 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6438 glDrawBuffer(buffer
);
6439 checkGLcall("glDrawBuffer()");
6441 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6443 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6444 if(!src_swapchain
) {
6445 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6449 context_bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6450 context_attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6451 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6452 checkGLcall("glDrawBuffer()");
6453 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6454 checkGLcall("glFramebufferRenderbufferEXT");
6456 glDisable(GL_SCISSOR_TEST
);
6457 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6460 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6461 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6462 checkGLcall("glBlitFramebuffer()");
6464 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6465 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6466 checkGLcall("glBlitFramebuffer()");
6469 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6471 if (This
->activeContext
->current_fbo
) {
6472 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6474 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6475 checkGLcall("glBindFramebuffer()");
6478 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6479 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6480 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6481 glDrawBuffer(GL_BACK
);
6482 checkGLcall("glDrawBuffer()");
6487 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6489 WINED3DVIEWPORT viewport
;
6491 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6493 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6494 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6495 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6496 return WINED3DERR_INVALIDCALL
;
6499 /* MSDN says that null disables the render target
6500 but a device must always be associated with a render target
6501 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6503 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6504 FIXME("Trying to set render target 0 to NULL\n");
6505 return WINED3DERR_INVALIDCALL
;
6507 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6508 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
);
6509 return WINED3DERR_INVALIDCALL
;
6512 /* If we are trying to set what we already have, don't bother */
6513 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6514 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6517 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6518 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6519 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6521 /* Render target 0 is special */
6522 if(RenderTargetIndex
== 0) {
6523 /* Finally, reset the viewport as the MSDN states. */
6524 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6525 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6528 viewport
.MaxZ
= 1.0f
;
6529 viewport
.MinZ
= 0.0f
;
6530 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6531 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6532 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6534 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6539 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6540 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6541 HRESULT hr
= WINED3D_OK
;
6542 IWineD3DSurface
*tmp
;
6544 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6546 if (pNewZStencil
== This
->stencilBufferTarget
) {
6547 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6549 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6550 * depending on the renter target implementation being used.
6551 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6552 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6553 * stencil buffer and incur an extra memory overhead
6554 ******************************************************/
6556 if (This
->stencilBufferTarget
) {
6557 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6558 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
6559 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
6561 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6562 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6563 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6567 tmp
= This
->stencilBufferTarget
;
6568 This
->stencilBufferTarget
= pNewZStencil
;
6569 /* should we be calling the parent or the wined3d surface? */
6570 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6571 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6574 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6575 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6576 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6577 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6578 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6585 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6586 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6587 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6588 /* TODO: the use of Impl is deprecated. */
6589 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6590 WINED3DLOCKED_RECT lockedRect
;
6592 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6594 /* some basic validation checks */
6595 if(This
->cursorTexture
) {
6596 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6598 glDeleteTextures(1, &This
->cursorTexture
);
6600 This
->cursorTexture
= 0;
6603 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6604 This
->haveHardwareCursor
= TRUE
;
6606 This
->haveHardwareCursor
= FALSE
;
6609 WINED3DLOCKED_RECT rect
;
6611 /* MSDN: Cursor must be A8R8G8B8 */
6612 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6613 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6614 return WINED3DERR_INVALIDCALL
;
6617 /* MSDN: Cursor must be smaller than the display mode */
6618 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6619 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6620 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
);
6621 return WINED3DERR_INVALIDCALL
;
6624 if (!This
->haveHardwareCursor
) {
6625 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6627 /* Do not store the surface's pointer because the application may
6628 * release it after setting the cursor image. Windows doesn't
6629 * addref the set surface, so we can't do this either without
6630 * creating circular refcount dependencies. Copy out the gl texture
6633 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6634 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6635 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6637 const struct GlPixelFormatDesc
*glDesc
;
6638 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6639 char *mem
, *bits
= (char *)rect
.pBits
;
6640 GLint intfmt
= glDesc
->glInternal
;
6641 GLint format
= glDesc
->glFormat
;
6642 GLint type
= glDesc
->glType
;
6643 INT height
= This
->cursorHeight
;
6644 INT width
= This
->cursorWidth
;
6645 INT bpp
= tableEntry
->bpp
;
6648 /* Reformat the texture memory (pitch and width can be
6650 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6651 for(i
= 0; i
< height
; i
++)
6652 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6653 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6656 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6657 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6658 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6661 /* Make sure that a proper texture unit is selected */
6662 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6663 checkGLcall("glActiveTextureARB");
6664 sampler
= This
->rev_tex_unit_map
[0];
6665 if (sampler
!= -1) {
6666 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6668 /* Create a new cursor texture */
6669 glGenTextures(1, &This
->cursorTexture
);
6670 checkGLcall("glGenTextures");
6671 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6672 checkGLcall("glBindTexture");
6673 /* Copy the bitmap memory into the cursor texture */
6674 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6675 HeapFree(GetProcessHeap(), 0, mem
);
6676 checkGLcall("glTexImage2D");
6678 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6679 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6680 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6687 FIXME("A cursor texture was not returned.\n");
6688 This
->cursorTexture
= 0;
6693 /* Draw a hardware cursor */
6694 ICONINFO cursorInfo
;
6696 /* Create and clear maskBits because it is not needed for
6697 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6699 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6700 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6701 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6702 WINED3DLOCK_NO_DIRTY_UPDATE
|
6703 WINED3DLOCK_READONLY
6705 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6706 pSur
->currentDesc
.Height
);
6708 cursorInfo
.fIcon
= FALSE
;
6709 cursorInfo
.xHotspot
= XHotSpot
;
6710 cursorInfo
.yHotspot
= YHotSpot
;
6711 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6712 pSur
->currentDesc
.Height
, 1,
6714 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6715 pSur
->currentDesc
.Height
, 1,
6716 32, lockedRect
.pBits
);
6717 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6718 /* Create our cursor and clean up. */
6719 cursor
= CreateIconIndirect(&cursorInfo
);
6721 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6722 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6723 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6724 This
->hardwareCursor
= cursor
;
6725 HeapFree(GetProcessHeap(), 0, maskBits
);
6729 This
->xHotSpot
= XHotSpot
;
6730 This
->yHotSpot
= YHotSpot
;
6734 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6735 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6736 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6738 This
->xScreenSpace
= XScreenSpace
;
6739 This
->yScreenSpace
= YScreenSpace
;
6745 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6746 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6747 BOOL oldVisible
= This
->bCursorVisible
;
6750 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6753 * When ShowCursor is first called it should make the cursor appear at the OS's last
6754 * known cursor position. Because of this, some applications just repetitively call
6755 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6758 This
->xScreenSpace
= pt
.x
;
6759 This
->yScreenSpace
= pt
.y
;
6761 if (This
->haveHardwareCursor
) {
6762 This
->bCursorVisible
= bShow
;
6764 SetCursor(This
->hardwareCursor
);
6770 if (This
->cursorTexture
)
6771 This
->bCursorVisible
= bShow
;
6777 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6778 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6779 IWineD3DResourceImpl
*resource
;
6780 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6782 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6783 switch (This
->state
) {
6786 case WINED3DERR_DEVICELOST
:
6788 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6789 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
6790 return WINED3DERR_DEVICENOTRESET
;
6792 return WINED3DERR_DEVICELOST
;
6794 case WINED3DERR_DRIVERINTERNALERROR
:
6795 return WINED3DERR_DRIVERINTERNALERROR
;
6799 return WINED3DERR_DRIVERINTERNALERROR
;
6803 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6804 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6805 /** FIXME: Resource tracking needs to be done,
6806 * The closes we can do to this is set the priorities of all managed textures low
6807 * and then reset them.
6808 ***********************************************************/
6809 FIXME("(%p) : stub\n", This
);
6813 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6815 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6817 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6818 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6819 /* Release the DC */
6820 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6821 DeleteDC(surface
->hDC
);
6822 /* Release the DIB section */
6823 DeleteObject(surface
->dib
.DIBsection
);
6824 surface
->dib
.bitmap_data
= NULL
;
6825 surface
->resource
.allocatedMemory
= NULL
;
6826 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6828 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6829 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
6831 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
6832 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6833 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6835 surface
->pow2Width
= surface
->pow2Height
= 1;
6836 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6837 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6839 surface
->glRect
.left
= 0;
6840 surface
->glRect
.top
= 0;
6841 surface
->glRect
.right
= surface
->pow2Width
;
6842 surface
->glRect
.bottom
= surface
->pow2Height
;
6844 if(surface
->glDescription
.textureName
) {
6845 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6847 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6849 surface
->glDescription
.textureName
= 0;
6850 surface
->Flags
&= ~SFLAG_CLIENT
;
6852 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6853 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6854 surface
->Flags
|= SFLAG_NONPOW2
;
6856 surface
->Flags
&= ~SFLAG_NONPOW2
;
6858 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6859 surface
->resource
.allocatedMemory
= NULL
;
6860 surface
->resource
.heapMemory
= NULL
;
6861 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6862 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6863 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
6864 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
6866 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
6870 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6871 TRACE("Unloading resource %p\n", resource
);
6872 IWineD3DResource_UnLoad(resource
);
6873 IWineD3DResource_Release(resource
);
6877 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6880 WINED3DDISPLAYMODE m
;
6883 /* All Windowed modes are supported, as is leaving the current mode */
6884 if(pp
->Windowed
) return TRUE
;
6885 if(!pp
->BackBufferWidth
) return TRUE
;
6886 if(!pp
->BackBufferHeight
) return TRUE
;
6888 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
6889 for(i
= 0; i
< count
; i
++) {
6890 memset(&m
, 0, sizeof(m
));
6891 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
6893 ERR("EnumAdapterModes failed\n");
6895 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6896 /* Mode found, it is supported */
6900 /* Mode not found -> not supported */
6904 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6905 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6906 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6908 IWineD3DBaseShaderImpl
*shader
;
6910 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6911 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6912 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
6916 if(This
->depth_blt_texture
) {
6917 glDeleteTextures(1, &This
->depth_blt_texture
);
6918 This
->depth_blt_texture
= 0;
6920 if (This
->depth_blt_rb
) {
6921 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
6922 This
->depth_blt_rb
= 0;
6923 This
->depth_blt_rb_w
= 0;
6924 This
->depth_blt_rb_h
= 0;
6928 This
->blitter
->free_private(iface
);
6929 This
->frag_pipe
->free_private(iface
);
6930 This
->shader_backend
->shader_free_private(iface
);
6933 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
6934 /* Textures are recreated below */
6935 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
6936 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6937 This
->dummyTextureName
[i
] = 0;
6941 while(This
->numContexts
) {
6942 DestroyContext(This
, This
->contexts
[0]);
6944 This
->activeContext
= NULL
;
6945 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6946 swapchain
->context
= NULL
;
6947 swapchain
->num_contexts
= 0;
6950 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6951 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6952 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6954 IWineD3DSurfaceImpl
*target
;
6956 /* Recreate the primary swapchain's context */
6957 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6958 if(swapchain
->backBuffer
) {
6959 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
6961 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
6963 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
6964 &swapchain
->presentParms
);
6965 swapchain
->num_contexts
= 1;
6966 This
->activeContext
= swapchain
->context
[0];
6968 create_dummy_textures(This
);
6970 hr
= This
->shader_backend
->shader_alloc_private(iface
);
6972 ERR("Failed to recreate shader private data\n");
6975 hr
= This
->frag_pipe
->alloc_private(iface
);
6977 TRACE("Fragment pipeline private data couldn't be allocated\n");
6980 hr
= This
->blitter
->alloc_private(iface
);
6982 TRACE("Blitter private data couldn't be allocated\n");
6989 This
->blitter
->free_private(iface
);
6990 This
->frag_pipe
->free_private(iface
);
6991 This
->shader_backend
->shader_free_private(iface
);
6995 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6996 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6997 IWineD3DSwapChainImpl
*swapchain
;
6999 BOOL DisplayModeChanged
= FALSE
;
7000 WINED3DDISPLAYMODE mode
;
7001 TRACE("(%p)\n", This
);
7003 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7005 ERR("Failed to get the first implicit swapchain\n");
7009 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7010 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7011 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7012 pPresentationParameters
->BackBufferHeight
);
7013 return WINED3DERR_INVALIDCALL
;
7016 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7017 * on an existing gl context, so there's no real need for recreation.
7019 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7021 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7023 TRACE("New params:\n");
7024 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7025 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7026 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7027 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7028 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7029 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7030 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7031 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7032 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7033 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7034 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7035 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7036 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7038 /* No special treatment of these parameters. Just store them */
7039 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7040 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7041 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7042 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7044 /* What to do about these? */
7045 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7046 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7047 ERR("Cannot change the back buffer count yet\n");
7049 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7050 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7051 ERR("Cannot change the back buffer format yet\n");
7053 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7054 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7055 ERR("Cannot change the device window yet\n");
7057 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
7058 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7059 return WINED3DERR_INVALIDCALL
;
7062 /* Reset the depth stencil */
7063 if (pPresentationParameters
->EnableAutoDepthStencil
)
7064 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
7066 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
7068 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
7070 if(pPresentationParameters
->Windowed
) {
7071 mode
.Width
= swapchain
->orig_width
;
7072 mode
.Height
= swapchain
->orig_height
;
7073 mode
.RefreshRate
= 0;
7074 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7076 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7077 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7078 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7079 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7082 /* Should Width == 800 && Height == 0 set 800x600? */
7083 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7084 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7085 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7089 if(!pPresentationParameters
->Windowed
) {
7090 DisplayModeChanged
= TRUE
;
7092 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7093 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7095 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7096 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7097 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7099 if(This
->auto_depth_stencil_buffer
) {
7100 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7104 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7105 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7106 DisplayModeChanged
) {
7108 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7110 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
7111 if(swapchain
->presentParms
.Windowed
) {
7112 /* switch from windowed to fs */
7113 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7114 pPresentationParameters
->BackBufferWidth
,
7115 pPresentationParameters
->BackBufferHeight
);
7117 /* Fullscreen -> fullscreen mode change */
7118 MoveWindow(swapchain
->win_handle
, 0, 0,
7119 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
7122 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
7123 /* Fullscreen -> windowed switch */
7124 IWineD3DDeviceImpl_RestoreWindow(iface
, swapchain
->win_handle
);
7126 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7127 } else if(!pPresentationParameters
->Windowed
) {
7128 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7129 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7130 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7131 * Reset to clear up their mess. Guild Wars also loses the device during that.
7135 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7136 pPresentationParameters
->BackBufferWidth
,
7137 pPresentationParameters
->BackBufferHeight
);
7138 This
->style
= style
;
7139 This
->exStyle
= exStyle
;
7142 TRACE("Resetting stateblock\n");
7143 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
7144 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
7146 /* Note: No parent needed for initial internal stateblock */
7147 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
7148 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7149 else TRACE("Created stateblock %p\n", This
->stateBlock
);
7150 This
->updateStateBlock
= This
->stateBlock
;
7151 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
7153 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7155 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7158 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
7159 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7161 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7167 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7168 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7169 /** FIXME: always true at the moment **/
7170 if(!bEnableDialogs
) {
7171 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7177 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7178 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7179 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7181 *pParameters
= This
->createParms
;
7185 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7186 IWineD3DSwapChain
*swapchain
;
7188 TRACE("Relaying to swapchain\n");
7190 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7191 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
7192 IWineD3DSwapChain_Release(swapchain
);
7197 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7198 IWineD3DSwapChain
*swapchain
;
7200 TRACE("Relaying to swapchain\n");
7202 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7203 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7204 IWineD3DSwapChain_Release(swapchain
);
7210 /** ********************************************************
7211 * Notification functions
7212 ** ********************************************************/
7213 /** This function must be called in the release of a resource when ref == 0,
7214 * the contents of resource must still be correct,
7215 * any handles to other resource held by the caller must be closed
7216 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7217 *****************************************************/
7218 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7219 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7221 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7222 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7225 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7226 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7228 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7230 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7234 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7235 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7236 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
7239 TRACE("(%p) : resource %p\n", This
, resource
);
7241 context_resource_released(iface
, resource
, type
);
7244 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7245 case WINED3DRTYPE_SURFACE
: {
7248 /* Cleanup any FBO attachments if d3d is enabled */
7249 if(This
->d3d_initialized
) {
7250 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7251 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7253 TRACE("Last active render target destroyed\n");
7254 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7255 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7256 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7257 * and the lastActiveRenderTarget member shouldn't matter
7260 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7261 TRACE("Activating primary back buffer\n");
7262 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7263 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7264 /* Single buffering environment */
7265 TRACE("Activating primary front buffer\n");
7266 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7268 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7269 /* Implicit render target destroyed, that means the device is being destroyed
7270 * whatever we set here, it shouldn't matter
7272 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7275 /* May happen during ddraw uninitialization */
7276 TRACE("Render target set, but swapchain does not exist!\n");
7277 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7281 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7282 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
7283 This
->render_targets
[i
] = NULL
;
7286 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
7287 This
->stencilBufferTarget
= NULL
;
7293 case WINED3DRTYPE_TEXTURE
:
7294 case WINED3DRTYPE_CUBETEXTURE
:
7295 case WINED3DRTYPE_VOLUMETEXTURE
:
7296 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7297 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7298 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7299 This
->stateBlock
->textures
[counter
] = NULL
;
7301 if (This
->updateStateBlock
!= This
->stateBlock
){
7302 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7303 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7304 This
->updateStateBlock
->textures
[counter
] = NULL
;
7309 case WINED3DRTYPE_VOLUME
:
7310 /* TODO: nothing really? */
7312 case WINED3DRTYPE_VERTEXBUFFER
:
7313 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7316 TRACE("Cleaning up stream pointers\n");
7318 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7319 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7320 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7322 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7323 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7324 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7325 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7326 /* Set changed flag? */
7329 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) */
7330 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7331 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7332 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7338 case WINED3DRTYPE_INDEXBUFFER
:
7339 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7340 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7341 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7342 This
->updateStateBlock
->pIndexData
= NULL
;
7345 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7346 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7347 This
->stateBlock
->pIndexData
= NULL
;
7353 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7358 /* Remove the resource from the resourceStore */
7359 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7361 TRACE("Resource released\n");
7365 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7366 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7367 IWineD3DResourceImpl
*resource
, *cursor
;
7369 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7371 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7372 TRACE("enumerating resource %p\n", resource
);
7373 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7374 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7375 if(ret
== S_FALSE
) {
7376 TRACE("Canceling enumeration\n");
7383 /**********************************************************
7384 * IWineD3DDevice VTbl follows
7385 **********************************************************/
7387 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7389 /*** IUnknown methods ***/
7390 IWineD3DDeviceImpl_QueryInterface
,
7391 IWineD3DDeviceImpl_AddRef
,
7392 IWineD3DDeviceImpl_Release
,
7393 /*** IWineD3DDevice methods ***/
7394 IWineD3DDeviceImpl_GetParent
,
7395 /*** Creation methods**/
7396 IWineD3DDeviceImpl_CreateVertexBuffer
,
7397 IWineD3DDeviceImpl_CreateIndexBuffer
,
7398 IWineD3DDeviceImpl_CreateStateBlock
,
7399 IWineD3DDeviceImpl_CreateSurface
,
7400 IWineD3DDeviceImpl_CreateTexture
,
7401 IWineD3DDeviceImpl_CreateVolumeTexture
,
7402 IWineD3DDeviceImpl_CreateVolume
,
7403 IWineD3DDeviceImpl_CreateCubeTexture
,
7404 IWineD3DDeviceImpl_CreateQuery
,
7405 IWineD3DDeviceImpl_CreateSwapChain
,
7406 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7407 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7408 IWineD3DDeviceImpl_CreateVertexShader
,
7409 IWineD3DDeviceImpl_CreatePixelShader
,
7410 IWineD3DDeviceImpl_CreatePalette
,
7411 /*** Odd functions **/
7412 IWineD3DDeviceImpl_Init3D
,
7413 IWineD3DDeviceImpl_InitGDI
,
7414 IWineD3DDeviceImpl_Uninit3D
,
7415 IWineD3DDeviceImpl_UninitGDI
,
7416 IWineD3DDeviceImpl_SetMultithreaded
,
7417 IWineD3DDeviceImpl_EvictManagedResources
,
7418 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7419 IWineD3DDeviceImpl_GetBackBuffer
,
7420 IWineD3DDeviceImpl_GetCreationParameters
,
7421 IWineD3DDeviceImpl_GetDeviceCaps
,
7422 IWineD3DDeviceImpl_GetDirect3D
,
7423 IWineD3DDeviceImpl_GetDisplayMode
,
7424 IWineD3DDeviceImpl_SetDisplayMode
,
7425 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7426 IWineD3DDeviceImpl_GetRasterStatus
,
7427 IWineD3DDeviceImpl_GetSwapChain
,
7428 IWineD3DDeviceImpl_Reset
,
7429 IWineD3DDeviceImpl_SetDialogBoxMode
,
7430 IWineD3DDeviceImpl_SetCursorProperties
,
7431 IWineD3DDeviceImpl_SetCursorPosition
,
7432 IWineD3DDeviceImpl_ShowCursor
,
7433 IWineD3DDeviceImpl_TestCooperativeLevel
,
7434 /*** Getters and setters **/
7435 IWineD3DDeviceImpl_SetClipPlane
,
7436 IWineD3DDeviceImpl_GetClipPlane
,
7437 IWineD3DDeviceImpl_SetClipStatus
,
7438 IWineD3DDeviceImpl_GetClipStatus
,
7439 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7440 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7441 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7442 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7443 IWineD3DDeviceImpl_SetGammaRamp
,
7444 IWineD3DDeviceImpl_GetGammaRamp
,
7445 IWineD3DDeviceImpl_SetIndices
,
7446 IWineD3DDeviceImpl_GetIndices
,
7447 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7448 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7449 IWineD3DDeviceImpl_SetLight
,
7450 IWineD3DDeviceImpl_GetLight
,
7451 IWineD3DDeviceImpl_SetLightEnable
,
7452 IWineD3DDeviceImpl_GetLightEnable
,
7453 IWineD3DDeviceImpl_SetMaterial
,
7454 IWineD3DDeviceImpl_GetMaterial
,
7455 IWineD3DDeviceImpl_SetNPatchMode
,
7456 IWineD3DDeviceImpl_GetNPatchMode
,
7457 IWineD3DDeviceImpl_SetPaletteEntries
,
7458 IWineD3DDeviceImpl_GetPaletteEntries
,
7459 IWineD3DDeviceImpl_SetPixelShader
,
7460 IWineD3DDeviceImpl_GetPixelShader
,
7461 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7462 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7463 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7464 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7465 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7466 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7467 IWineD3DDeviceImpl_SetRenderState
,
7468 IWineD3DDeviceImpl_GetRenderState
,
7469 IWineD3DDeviceImpl_SetRenderTarget
,
7470 IWineD3DDeviceImpl_GetRenderTarget
,
7471 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7472 IWineD3DDeviceImpl_SetSamplerState
,
7473 IWineD3DDeviceImpl_GetSamplerState
,
7474 IWineD3DDeviceImpl_SetScissorRect
,
7475 IWineD3DDeviceImpl_GetScissorRect
,
7476 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7477 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7478 IWineD3DDeviceImpl_SetStreamSource
,
7479 IWineD3DDeviceImpl_GetStreamSource
,
7480 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7481 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7482 IWineD3DDeviceImpl_SetTexture
,
7483 IWineD3DDeviceImpl_GetTexture
,
7484 IWineD3DDeviceImpl_SetTextureStageState
,
7485 IWineD3DDeviceImpl_GetTextureStageState
,
7486 IWineD3DDeviceImpl_SetTransform
,
7487 IWineD3DDeviceImpl_GetTransform
,
7488 IWineD3DDeviceImpl_SetVertexDeclaration
,
7489 IWineD3DDeviceImpl_GetVertexDeclaration
,
7490 IWineD3DDeviceImpl_SetVertexShader
,
7491 IWineD3DDeviceImpl_GetVertexShader
,
7492 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7493 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7494 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7495 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7496 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7497 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7498 IWineD3DDeviceImpl_SetViewport
,
7499 IWineD3DDeviceImpl_GetViewport
,
7500 IWineD3DDeviceImpl_MultiplyTransform
,
7501 IWineD3DDeviceImpl_ValidateDevice
,
7502 IWineD3DDeviceImpl_ProcessVertices
,
7503 /*** State block ***/
7504 IWineD3DDeviceImpl_BeginStateBlock
,
7505 IWineD3DDeviceImpl_EndStateBlock
,
7506 /*** Scene management ***/
7507 IWineD3DDeviceImpl_BeginScene
,
7508 IWineD3DDeviceImpl_EndScene
,
7509 IWineD3DDeviceImpl_Present
,
7510 IWineD3DDeviceImpl_Clear
,
7512 IWineD3DDeviceImpl_DrawPrimitive
,
7513 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7514 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7515 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7516 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7517 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7518 IWineD3DDeviceImpl_DrawRectPatch
,
7519 IWineD3DDeviceImpl_DrawTriPatch
,
7520 IWineD3DDeviceImpl_DeletePatch
,
7521 IWineD3DDeviceImpl_ColorFill
,
7522 IWineD3DDeviceImpl_UpdateTexture
,
7523 IWineD3DDeviceImpl_UpdateSurface
,
7524 IWineD3DDeviceImpl_GetFrontBufferData
,
7525 /*** object tracking ***/
7526 IWineD3DDeviceImpl_ResourceReleased
,
7527 IWineD3DDeviceImpl_EnumResources
7530 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7531 WINED3DRS_ALPHABLENDENABLE
,
7532 WINED3DRS_ALPHAFUNC
,
7533 WINED3DRS_ALPHAREF
,
7534 WINED3DRS_ALPHATESTENABLE
,
7536 WINED3DRS_COLORWRITEENABLE
,
7537 WINED3DRS_DESTBLEND
,
7538 WINED3DRS_DITHERENABLE
,
7539 WINED3DRS_FILLMODE
,
7540 WINED3DRS_FOGDENSITY
,
7542 WINED3DRS_FOGSTART
,
7543 WINED3DRS_LASTPIXEL
,
7544 WINED3DRS_SHADEMODE
,
7545 WINED3DRS_SRCBLEND
,
7546 WINED3DRS_STENCILENABLE
,
7547 WINED3DRS_STENCILFAIL
,
7548 WINED3DRS_STENCILFUNC
,
7549 WINED3DRS_STENCILMASK
,
7550 WINED3DRS_STENCILPASS
,
7551 WINED3DRS_STENCILREF
,
7552 WINED3DRS_STENCILWRITEMASK
,
7553 WINED3DRS_STENCILZFAIL
,
7554 WINED3DRS_TEXTUREFACTOR
,
7565 WINED3DRS_ZWRITEENABLE
7568 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7569 WINED3DTSS_ADDRESSW
,
7570 WINED3DTSS_ALPHAARG0
,
7571 WINED3DTSS_ALPHAARG1
,
7572 WINED3DTSS_ALPHAARG2
,
7573 WINED3DTSS_ALPHAOP
,
7574 WINED3DTSS_BUMPENVLOFFSET
,
7575 WINED3DTSS_BUMPENVLSCALE
,
7576 WINED3DTSS_BUMPENVMAT00
,
7577 WINED3DTSS_BUMPENVMAT01
,
7578 WINED3DTSS_BUMPENVMAT10
,
7579 WINED3DTSS_BUMPENVMAT11
,
7580 WINED3DTSS_COLORARG0
,
7581 WINED3DTSS_COLORARG1
,
7582 WINED3DTSS_COLORARG2
,
7583 WINED3DTSS_COLOROP
,
7584 WINED3DTSS_RESULTARG
,
7585 WINED3DTSS_TEXCOORDINDEX
,
7586 WINED3DTSS_TEXTURETRANSFORMFLAGS
7589 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7590 WINED3DSAMP_ADDRESSU
,
7591 WINED3DSAMP_ADDRESSV
,
7592 WINED3DSAMP_ADDRESSW
,
7593 WINED3DSAMP_BORDERCOLOR
,
7594 WINED3DSAMP_MAGFILTER
,
7595 WINED3DSAMP_MINFILTER
,
7596 WINED3DSAMP_MIPFILTER
,
7597 WINED3DSAMP_MIPMAPLODBIAS
,
7598 WINED3DSAMP_MAXMIPLEVEL
,
7599 WINED3DSAMP_MAXANISOTROPY
,
7600 WINED3DSAMP_SRGBTEXTURE
,
7601 WINED3DSAMP_ELEMENTINDEX
7604 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7606 WINED3DRS_AMBIENTMATERIALSOURCE
,
7607 WINED3DRS_CLIPPING
,
7608 WINED3DRS_CLIPPLANEENABLE
,
7609 WINED3DRS_COLORVERTEX
,
7610 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7611 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7612 WINED3DRS_FOGDENSITY
,
7614 WINED3DRS_FOGSTART
,
7615 WINED3DRS_FOGTABLEMODE
,
7616 WINED3DRS_FOGVERTEXMODE
,
7617 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7618 WINED3DRS_LIGHTING
,
7619 WINED3DRS_LOCALVIEWER
,
7620 WINED3DRS_MULTISAMPLEANTIALIAS
,
7621 WINED3DRS_MULTISAMPLEMASK
,
7622 WINED3DRS_NORMALIZENORMALS
,
7623 WINED3DRS_PATCHEDGESTYLE
,
7624 WINED3DRS_POINTSCALE_A
,
7625 WINED3DRS_POINTSCALE_B
,
7626 WINED3DRS_POINTSCALE_C
,
7627 WINED3DRS_POINTSCALEENABLE
,
7628 WINED3DRS_POINTSIZE
,
7629 WINED3DRS_POINTSIZE_MAX
,
7630 WINED3DRS_POINTSIZE_MIN
,
7631 WINED3DRS_POINTSPRITEENABLE
,
7632 WINED3DRS_RANGEFOGENABLE
,
7633 WINED3DRS_SPECULARMATERIALSOURCE
,
7634 WINED3DRS_TWEENFACTOR
,
7635 WINED3DRS_VERTEXBLEND
,
7636 WINED3DRS_CULLMODE
,
7640 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7641 WINED3DTSS_TEXCOORDINDEX
,
7642 WINED3DTSS_TEXTURETRANSFORMFLAGS
7645 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7646 WINED3DSAMP_DMAPOFFSET
7649 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7650 DWORD rep
= This
->StateTable
[state
].representative
;
7654 WineD3DContext
*context
;
7657 for(i
= 0; i
< This
->numContexts
; i
++) {
7658 context
= This
->contexts
[i
];
7659 if(isStateDirty(context
, rep
)) continue;
7661 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7664 context
->isStateDirty
[idx
] |= (1 << shift
);
7668 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7669 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7670 /* The drawable size of a pbuffer render target is the current pbuffer size
7672 *width
= dev
->pbufferWidth
;
7673 *height
= dev
->pbufferHeight
;
7676 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7677 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7679 *width
= This
->pow2Width
;
7680 *height
= This
->pow2Height
;
7683 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7684 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7685 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7686 * current context's drawable, which is the size of the back buffer of the swapchain
7687 * the active context belongs to. The back buffer of the swapchain is stored as the
7688 * surface the context belongs to.
7690 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
7691 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;