2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
138 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
140 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
141 if (IsEqualGUID(riid
, &IID_IUnknown
)
142 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
143 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
144 IUnknown_AddRef(iface
);
149 return E_NOINTERFACE
;
152 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
154 ULONG refCount
= InterlockedIncrement(&This
->ref
);
156 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
160 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
161 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
162 ULONG refCount
= InterlockedDecrement(&This
->ref
);
164 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This
->resources
)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
173 dumpResources(&This
->resources
);
176 if(This
->contexts
) ERR("Context array not freed!\n");
177 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
178 This
->haveHardwareCursor
= FALSE
;
180 IWineD3D_Release(This
->wineD3D
);
181 This
->wineD3D
= NULL
;
182 HeapFree(GetProcessHeap(), 0, This
);
183 TRACE("Freed device %p\n", This
);
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
193 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
194 *pParent
= This
->parent
;
195 IUnknown_AddRef(This
->parent
);
199 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
200 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
202 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
203 IWineD3DVertexBufferImpl
*object
;
204 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
205 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer
= NULL
;
211 return WINED3DERR_INVALIDCALL
;
212 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer
= NULL
;
218 return WINED3DERR_INVALIDCALL
;
221 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
223 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
224 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion
<= 7 && conv
) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
253 object
->Flags
|= VBFLAG_CREATEVBO
;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
259 GLenum error
, glUsage
;
260 TRACE("Creating VBO for Index Buffer %p\n", object
);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
273 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
274 error
= glGetError();
275 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
281 error
= glGetError();
282 if(error
!= GL_NO_ERROR
) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage
= GL_STATIC_DRAW_ARB
;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
292 error
= glGetError();
293 if(error
!= GL_NO_ERROR
) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
298 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
308 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
309 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
310 HANDLE
*sharedHandle
, IUnknown
*parent
) {
311 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
312 IWineD3DIndexBufferImpl
*object
;
313 TRACE("(%p) Creating index buffer\n", This
);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
318 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
319 CreateIndexBufferVBO(This
, object
);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
323 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
324 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
329 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
332 IWineD3DStateBlockImpl
*object
;
336 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
337 object
->blockType
= Type
;
339 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
340 list_init(&object
->lightMap
[i
]);
343 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type
== WINED3DSBT_INIT
) {
346 /* Don't bother increasing the reference count otherwise a device will never
347 be freed due to circular dependencies */
351 temp_result
= allocate_shader_constants(object
);
352 if (WINED3D_OK
!= temp_result
)
355 /* Otherwise, might as well set the whole state block to the appropriate values */
356 if (This
->stateBlock
!= NULL
)
357 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
359 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
361 /* Reset the ref and type after kludging it */
362 object
->wineD3DDevice
= This
;
364 object
->blockType
= Type
;
366 TRACE("Updating changed flags appropriate for type %d\n", Type
);
368 if (Type
== WINED3DSBT_ALL
) {
370 TRACE("ALL => Pretend everything has changed\n");
371 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
373 /* Lights are not part of the changed / set structure */
374 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
376 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
377 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
378 light
->changed
= TRUE
;
379 light
->enabledChanged
= TRUE
;
382 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
383 object
->contained_render_states
[j
- 1] = j
;
385 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
386 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
387 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
388 object
->contained_transform_states
[j
- 1] = j
;
390 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
391 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
392 object
->contained_vs_consts_f
[j
] = j
;
394 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
395 for(j
= 0; j
< MAX_CONST_I
; j
++) {
396 object
->contained_vs_consts_i
[j
] = j
;
398 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
399 for(j
= 0; j
< MAX_CONST_B
; j
++) {
400 object
->contained_vs_consts_b
[j
] = j
;
402 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
403 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
404 object
->contained_ps_consts_f
[j
] = j
;
406 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
407 for(j
= 0; j
< MAX_CONST_I
; j
++) {
408 object
->contained_ps_consts_i
[j
] = j
;
410 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
411 for(j
= 0; j
< MAX_CONST_B
; j
++) {
412 object
->contained_ps_consts_b
[j
] = j
;
414 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
415 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
416 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
417 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
418 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
419 object
->num_contained_tss_states
++;
422 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
423 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
424 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
425 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
426 object
->num_contained_sampler_states
++;
430 for(i
= 0; i
< MAX_STREAMS
; i
++) {
431 if(object
->streamSource
[i
]) {
432 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
435 if(object
->pIndexData
) {
436 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
438 if(object
->vertexShader
) {
439 IWineD3DVertexShader_AddRef(object
->vertexShader
);
441 if(object
->pixelShader
) {
442 IWineD3DPixelShader_AddRef(object
->pixelShader
);
445 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
447 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
448 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
450 object
->changed
.pixelShader
= TRUE
;
452 /* Pixel Shader Constants */
453 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
) {
454 object
->contained_ps_consts_f
[i
] = i
;
455 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
457 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
458 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
459 object
->contained_ps_consts_b
[i
] = i
;
460 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
462 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
463 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
464 object
->contained_ps_consts_i
[i
] = i
;
465 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
467 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
469 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
470 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
471 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
473 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
474 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
475 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
476 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
477 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
478 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
479 object
->num_contained_tss_states
++;
482 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
483 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
484 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
485 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
486 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
487 object
->num_contained_sampler_states
++;
490 if(object
->pixelShader
) {
491 IWineD3DPixelShader_AddRef(object
->pixelShader
);
494 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
495 * on them. This makes releasing the buffer easier
497 for(i
= 0; i
< MAX_STREAMS
; i
++) {
498 object
->streamSource
[i
] = NULL
;
500 object
->pIndexData
= NULL
;
501 object
->vertexShader
= NULL
;
503 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
505 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
506 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
508 object
->changed
.vertexShader
= TRUE
;
510 /* Vertex Shader Constants */
511 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
512 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
513 object
->contained_vs_consts_f
[i
] = i
;
515 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
516 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
517 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
518 object
->contained_vs_consts_b
[i
] = i
;
520 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
521 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
522 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
523 object
->contained_vs_consts_i
[i
] = i
;
525 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
526 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
527 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
528 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
530 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
531 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
532 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
533 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
534 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
535 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
536 object
->num_contained_tss_states
++;
539 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
540 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
541 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
542 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
543 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
544 object
->num_contained_sampler_states
++;
548 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
550 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
551 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
552 light
->changed
= TRUE
;
553 light
->enabledChanged
= TRUE
;
557 for(i
= 0; i
< MAX_STREAMS
; i
++) {
558 if(object
->streamSource
[i
]) {
559 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
562 if(object
->vertexShader
) {
563 IWineD3DVertexShader_AddRef(object
->vertexShader
);
565 object
->pIndexData
= NULL
;
566 object
->pixelShader
= NULL
;
568 FIXME("Unrecognized state block type %d\n", Type
);
571 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
575 /* ************************************
577 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
580 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
582 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
584 ******************************** */
586 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,WINED3DRESOURCETYPE Type
, DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
,DWORD MultisampleQuality
, HANDLE
* pSharedHandle
, WINED3DSURFTYPE Impl
, IUnknown
*parent
) {
587 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
588 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
589 unsigned int Size
= 1;
590 const GlPixelFormatDesc
*glDesc
;
591 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
593 TRACE("(%p) Create surface\n",This
);
595 /** FIXME: Check ranges on the inputs are valid
598 * [in] Quality level. The valid range is between zero and one less than the level
599 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
600 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
601 * values of paired render targets, depth stencil surfaces, and the MultiSample type
603 *******************************/
608 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
610 * If this flag is set, the contents of the depth stencil buffer will be
611 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
612 * with a different depth surface.
614 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
615 ***************************/
617 if(MultisampleQuality
> 0) {
618 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
619 MultisampleQuality
=0;
622 /** FIXME: Check that the format is supported
624 *******************************/
626 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
627 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
629 *********************************/
630 mul_4w
= (Width
+ 3) & ~3;
631 mul_4h
= (Height
+ 3) & ~3;
632 if (WINED3DFMT_UNKNOWN
== Format
) {
634 } else if (Format
== WINED3DFMT_DXT1
) {
635 /* DXT1 is half byte per pixel */
636 Size
= (mul_4w
* tableEntry
->bpp
* mul_4h
) >> 1;
638 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
639 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
||
640 Format
== WINED3DFMT_ATI2N
) {
641 Size
= (mul_4w
* tableEntry
->bpp
* mul_4h
);
643 /* The pitch is a multiple of 4 bytes */
644 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
648 if(glDesc
->heightscale
!= 0.0) Size
*= glDesc
->heightscale
;
650 /** Create and initialise the surface resource **/
651 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
652 /* "Standalone" surface */
653 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
655 object
->currentDesc
.Width
= Width
;
656 object
->currentDesc
.Height
= Height
;
657 object
->currentDesc
.MultiSampleType
= MultiSample
;
658 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
659 object
->glDescription
.level
= Level
;
660 object
->heightscale
= glDesc
->heightscale
!= 0.0 ? glDesc
->heightscale
: 1.0;
661 list_init(&object
->overlays
);
664 object
->Flags
= SFLAG_NORMCOORD
; /* Default to normalized coords */
665 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
666 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
667 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
670 if (WINED3DFMT_UNKNOWN
!= Format
) {
671 object
->bytesPerPixel
= tableEntry
->bpp
;
673 object
->bytesPerPixel
= 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
685 case WINED3DPOOL_SCRATCH
:
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
691 case WINED3DPOOL_SYSTEMMEM
:
692 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED
:
695 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
699 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
701 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
709 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
717 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
719 /* Look at the implementation and set the correct Vtable */
722 /* Check if a 3D adapter is available when creating gl surfaces */
724 ERR("OpenGL surfaces are not available without opengl\n");
725 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
726 HeapFree(GetProcessHeap(), 0, object
);
727 return WINED3DERR_NOTAVAILABLE
;
732 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
736 /* To be sure to catch this */
737 ERR("Unknown requested surface implementation %d!\n", Impl
);
738 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
739 return WINED3DERR_INVALIDCALL
;
742 list_init(&object
->renderbuffers
);
744 /* Call the private setup routine */
745 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
749 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
750 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
751 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
752 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
754 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
755 IWineD3DTextureImpl
*object
;
760 unsigned int pow2Width
;
761 unsigned int pow2Height
;
762 const GlPixelFormatDesc
*glDesc
;
763 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
765 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
766 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
767 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
769 /* TODO: It should only be possible to create textures for formats
770 that are reported as supported */
771 if (WINED3DFMT_UNKNOWN
>= Format
) {
772 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
773 return WINED3DERR_INVALIDCALL
;
776 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
777 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
778 object
->width
= Width
;
779 object
->height
= Height
;
781 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
782 object
->baseTexture
.minMipLookup
= &minMipLookup
;
783 object
->baseTexture
.magLookup
= &magLookup
;
785 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
786 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
789 /** Non-power2 support **/
790 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
794 /* Find the nearest pow2 match */
795 pow2Width
= pow2Height
= 1;
796 while (pow2Width
< Width
) pow2Width
<<= 1;
797 while (pow2Height
< Height
) pow2Height
<<= 1;
799 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
801 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
802 HeapFree(GetProcessHeap(), 0, object
);
804 return WINED3DERR_INVALIDCALL
;
811 /** FIXME: add support for real non-power-two if it's provided by the video card **/
812 /* Precalculated scaling for 'faked' non power of two texture coords.
813 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
814 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
815 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
817 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT
) && (Width
!= pow2Width
|| Height
!= pow2Height
)) {
818 object
->baseTexture
.pow2Matrix
[0] = 1.0;
819 object
->baseTexture
.pow2Matrix
[5] = 1.0;
820 object
->baseTexture
.pow2Matrix
[10] = 1.0;
821 object
->baseTexture
.pow2Matrix
[15] = 1.0;
822 object
->target
= GL_TEXTURE_2D
;
823 object
->cond_np2
= TRUE
;
824 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
825 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
826 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
827 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
829 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
830 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
831 object
->baseTexture
.pow2Matrix
[10] = 1.0;
832 object
->baseTexture
.pow2Matrix
[15] = 1.0;
833 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
834 object
->cond_np2
= TRUE
;
835 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
837 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
838 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
839 object
->baseTexture
.pow2Matrix
[10] = 1.0;
840 object
->baseTexture
.pow2Matrix
[15] = 1.0;
841 object
->target
= GL_TEXTURE_2D
;
842 object
->cond_np2
= FALSE
;
844 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
846 /* Calculate levels for mip mapping */
847 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
848 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
849 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
850 return WINED3DERR_INVALIDCALL
;
853 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL
;
856 object
->baseTexture
.levels
= 1;
857 } else if (Levels
== 0) {
858 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
859 object
->baseTexture
.levels
++;
862 while (tmpW
> 1 || tmpH
> 1) {
863 tmpW
= max(1, tmpW
>> 1);
864 tmpH
= max(1, tmpH
>> 1);
865 object
->baseTexture
.levels
++;
867 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
870 /* Generate all the surfaces */
873 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
875 /* use the callback to create the texture surface */
876 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
877 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
878 FIXME("Failed to create surface %p\n", object
);
880 object
->surfaces
[i
] = NULL
;
881 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
887 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
888 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
889 surface_set_texture_target(object
->surfaces
[i
], object
->target
);
890 /* calculate the next mipmap level */
891 tmpW
= max(1, tmpW
>> 1);
892 tmpH
= max(1, tmpH
>> 1);
894 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
896 TRACE("(%p) : Created texture %p\n", This
, object
);
900 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
901 UINT Width
, UINT Height
, UINT Depth
,
902 UINT Levels
, DWORD Usage
,
903 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
904 IWineD3DVolumeTexture
**ppVolumeTexture
,
905 HANDLE
*pSharedHandle
, IUnknown
*parent
,
906 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
908 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
909 IWineD3DVolumeTextureImpl
*object
;
914 const GlPixelFormatDesc
*glDesc
;
916 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
918 /* TODO: It should only be possible to create textures for formats
919 that are reported as supported */
920 if (WINED3DFMT_UNKNOWN
>= Format
) {
921 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
922 return WINED3DERR_INVALIDCALL
;
924 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
925 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
926 return WINED3DERR_INVALIDCALL
;
929 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
930 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
932 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
933 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
935 object
->width
= Width
;
936 object
->height
= Height
;
937 object
->depth
= Depth
;
939 /* Is NP2 support for volumes needed? */
940 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
941 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
942 object
->baseTexture
.pow2Matrix
[10] = 1.0;
943 object
->baseTexture
.pow2Matrix
[15] = 1.0;
945 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
946 object
->baseTexture
.minMipLookup
= &minMipLookup
;
947 object
->baseTexture
.magLookup
= &magLookup
;
949 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
950 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
953 /* Calculate levels for mip mapping */
954 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
955 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL
;
960 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL
;
963 object
->baseTexture
.levels
= 1;
964 } else if (Levels
== 0) {
965 object
->baseTexture
.levels
++;
969 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
970 tmpW
= max(1, tmpW
>> 1);
971 tmpH
= max(1, tmpH
>> 1);
972 tmpD
= max(1, tmpD
>> 1);
973 object
->baseTexture
.levels
++;
975 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
978 /* Generate all the surfaces */
983 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
986 /* Create the volume */
987 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
988 &object
->volumes
[i
], pSharedHandle
);
991 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
992 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
993 *ppVolumeTexture
= NULL
;
997 /* Set its container to this object */
998 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1000 /* calculate the next mipmap level */
1001 tmpW
= max(1, tmpW
>> 1);
1002 tmpH
= max(1, tmpH
>> 1);
1003 tmpD
= max(1, tmpD
>> 1);
1005 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1007 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1008 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1012 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1013 UINT Width
, UINT Height
, UINT Depth
,
1015 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1016 IWineD3DVolume
** ppVolume
,
1017 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1019 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1020 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1021 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1023 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1024 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1025 return WINED3DERR_INVALIDCALL
;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1030 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1031 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1033 object
->currentDesc
.Width
= Width
;
1034 object
->currentDesc
.Height
= Height
;
1035 object
->currentDesc
.Depth
= Depth
;
1036 object
->bytesPerPixel
= formatDesc
->bpp
;
1038 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1039 object
->lockable
= TRUE
;
1040 object
->locked
= FALSE
;
1041 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1042 object
->dirty
= TRUE
;
1044 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1047 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1048 UINT Levels
, DWORD Usage
,
1049 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1050 IWineD3DCubeTexture
**ppCubeTexture
,
1051 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1052 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1054 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1055 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1059 unsigned int pow2EdgeLength
;
1060 const GlPixelFormatDesc
*glDesc
;
1061 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1063 /* TODO: It should only be possible to create textures for formats
1064 that are reported as supported */
1065 if (WINED3DFMT_UNKNOWN
>= Format
) {
1066 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1067 return WINED3DERR_INVALIDCALL
;
1070 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1071 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1072 return WINED3DERR_INVALIDCALL
;
1075 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1076 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1078 TRACE("(%p) Create Cube Texture\n", This
);
1080 /* Find the nearest pow2 match */
1082 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1084 object
->edgeLength
= EdgeLength
;
1086 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
1087 /* Precalculated scaling for 'faked' non power of two texture coords */
1088 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
1089 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
1090 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1091 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1093 /* Precalculated scaling for 'faked' non power of two texture coords */
1094 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1095 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1096 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1097 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1100 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
1101 object
->baseTexture
.minMipLookup
= &minMipLookup
;
1102 object
->baseTexture
.magLookup
= &magLookup
;
1104 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
1105 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
1108 /* Calculate levels for mip mapping */
1109 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object
);
1113 *ppCubeTexture
= NULL
;
1115 return WINED3DERR_INVALIDCALL
;
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object
);
1120 *ppCubeTexture
= NULL
;
1122 return WINED3DERR_INVALIDCALL
;
1124 object
->baseTexture
.levels
= 1;
1125 } else if (Levels
== 0) {
1126 object
->baseTexture
.levels
++;
1129 tmpW
= max(1, tmpW
>> 1);
1130 object
->baseTexture
.levels
++;
1132 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1135 /* Generate all the surfaces */
1137 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1139 /* Create the 6 faces */
1140 for (j
= 0; j
< 6; j
++) {
1141 static const GLenum cube_targets
[6] = {
1142 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
1143 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
1144 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
1145 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
1146 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
1147 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1150 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1151 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1153 if(hr
!= WINED3D_OK
) {
1157 for (l
= 0; l
< j
; l
++) {
1158 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1160 for (k
= 0; k
< i
; k
++) {
1161 for (l
= 0; l
< 6; l
++) {
1162 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1166 FIXME("(%p) Failed to create surface\n",object
);
1167 HeapFree(GetProcessHeap(),0,object
);
1168 *ppCubeTexture
= NULL
;
1171 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1172 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1173 surface_set_texture_target(object
->surfaces
[j
][i
], cube_targets
[j
]);
1175 tmpW
= max(1, tmpW
>> 1);
1177 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1179 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1180 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1184 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1185 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1186 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1187 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1188 const IWineD3DQueryVtbl
*vtable
;
1190 /* Just a check to see if we support this type of query */
1192 case WINED3DQUERYTYPE_OCCLUSION
:
1193 TRACE("(%p) occlusion query\n", This
);
1194 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1197 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1199 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1202 case WINED3DQUERYTYPE_EVENT
:
1203 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1204 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1205 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1207 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1209 vtable
= &IWineD3DEventQuery_Vtbl
;
1213 case WINED3DQUERYTYPE_VCACHE
:
1214 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1215 case WINED3DQUERYTYPE_VERTEXSTATS
:
1216 case WINED3DQUERYTYPE_TIMESTAMP
:
1217 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1218 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1219 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1220 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1221 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1222 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1223 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1224 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1226 /* Use the base Query vtable until we have a special one for each query */
1227 vtable
= &IWineD3DQuery_Vtbl
;
1228 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1230 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1234 D3DCREATEOBJECTINSTANCE(object
, Query
)
1235 object
->lpVtbl
= vtable
;
1236 object
->type
= Type
;
1237 object
->state
= QUERY_CREATED
;
1238 /* allocated the 'extended' data based on the type of query requested */
1240 case WINED3DQUERYTYPE_OCCLUSION
:
1241 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1242 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1244 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1245 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1246 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1249 case WINED3DQUERYTYPE_EVENT
:
1250 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1251 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1253 if(GL_SUPPORT(APPLE_FENCE
)) {
1254 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1255 checkGLcall("glGenFencesAPPLE");
1256 } else if(GL_SUPPORT(NV_FENCE
)) {
1257 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1258 checkGLcall("glGenFencesNV");
1262 case WINED3DQUERYTYPE_VCACHE
:
1263 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1264 case WINED3DQUERYTYPE_VERTEXSTATS
:
1265 case WINED3DQUERYTYPE_TIMESTAMP
:
1266 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1267 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1268 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1269 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1270 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1271 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1272 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1273 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1275 object
->extendedData
= 0;
1276 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1278 TRACE("(%p) : Created Query %p\n", This
, object
);
1282 /*****************************************************************************
1283 * IWineD3DDeviceImpl_SetupFullscreenWindow
1285 * Helper function that modifies a HWND's Style and ExStyle for proper
1289 * iface: Pointer to the IWineD3DDevice interface
1290 * window: Window to setup
1292 *****************************************************************************/
1293 static LONG
fullscreen_style(LONG orig_style
) {
1294 LONG style
= orig_style
;
1295 style
&= ~WS_CAPTION
;
1296 style
&= ~WS_THICKFRAME
;
1298 /* Make sure the window is managed, otherwise we won't get keyboard input */
1299 style
|= WS_POPUP
| WS_SYSMENU
;
1304 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1305 LONG exStyle
= orig_exStyle
;
1307 /* Filter out window decorations */
1308 exStyle
&= ~WS_EX_WINDOWEDGE
;
1309 exStyle
&= ~WS_EX_CLIENTEDGE
;
1314 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
) {
1315 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1317 LONG style
, exStyle
;
1318 /* Don't do anything if an original style is stored.
1319 * That shouldn't happen
1321 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1322 if (This
->style
|| This
->exStyle
) {
1323 ERR("(%p): Want to change the window parameters of HWND %p, but "
1324 "another style is stored for restoration afterwards\n", This
, window
);
1327 /* Get the parameters and save them */
1328 style
= GetWindowLongW(window
, GWL_STYLE
);
1329 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1330 This
->style
= style
;
1331 This
->exStyle
= exStyle
;
1333 style
= fullscreen_style(style
);
1334 exStyle
= fullscreen_exStyle(exStyle
);
1336 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1337 This
->style
, This
->exStyle
, style
, exStyle
);
1339 SetWindowLongW(window
, GWL_STYLE
, style
);
1340 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1342 /* Inform the window about the update. */
1343 SetWindowPos(window
, HWND_TOP
, 0, 0,
1344 w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
);
1347 /*****************************************************************************
1348 * IWineD3DDeviceImpl_RestoreWindow
1350 * Helper function that restores a windows' properties when taking it out
1351 * of fullscreen mode
1354 * iface: Pointer to the IWineD3DDevice interface
1355 * window: Window to setup
1357 *****************************************************************************/
1358 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1360 LONG style
, exStyle
;
1362 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1363 * switch, do nothing
1365 if (!This
->style
&& !This
->exStyle
) return;
1367 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1368 This
, window
, This
->style
, This
->exStyle
);
1370 style
= GetWindowLongW(window
, GWL_STYLE
);
1371 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1373 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1374 * Some applications change it before calling Reset() when switching between windowed and
1375 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1377 if(style
== fullscreen_style(This
->style
) &&
1378 exStyle
== fullscreen_style(This
->exStyle
)) {
1379 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1380 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1383 /* Delete the old values */
1387 /* Inform the window about the update */
1388 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1389 0, 0, 0, 0, /* Pos, Size, ignored */
1390 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1393 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1394 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
* iface
,
1395 WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1396 IUnknown
* parent
, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1397 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
, WINED3DSURFTYPE surface_type
)
1399 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1402 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1404 IUnknown
*bufferParent
;
1405 BOOL displaymode_set
= FALSE
;
1406 WINED3DDISPLAYMODE Mode
;
1407 const StaticPixelFormatDesc
*formatDesc
;
1409 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1411 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1412 * does a device hold a reference to a swap chain giving them a lifetime of the device
1413 * or does the swap chain notify the device of its destruction.
1414 *******************************/
1416 /* Check the params */
1417 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1418 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1419 return WINED3DERR_INVALIDCALL
;
1420 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1421 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1424 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1425 switch(surface_type
) {
1427 object
->lpVtbl
= &IWineGDISwapChain_Vtbl
;
1429 case SURFACE_OPENGL
:
1430 object
->lpVtbl
= &IWineD3DSwapChain_Vtbl
;
1432 case SURFACE_UNKNOWN
:
1433 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1434 return WINED3DERR_INVALIDCALL
;
1437 /*********************
1438 * Lookup the window Handle and the relating X window handle
1439 ********************/
1441 /* Setup hwnd we are using, plus which display this equates to */
1442 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1443 if (!object
->win_handle
) {
1444 object
->win_handle
= This
->createParms
.hFocusWindow
;
1446 if(!pPresentationParameters
->Windowed
&& object
->win_handle
) {
1447 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
,
1448 pPresentationParameters
->BackBufferWidth
,
1449 pPresentationParameters
->BackBufferHeight
);
1452 hDc
= GetDC(object
->win_handle
);
1453 TRACE("Using hDc %p\n", hDc
);
1456 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1457 return WINED3DERR_NOTAVAILABLE
;
1460 /* Get info on the current display setup */
1461 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1462 object
->orig_width
= Mode
.Width
;
1463 object
->orig_height
= Mode
.Height
;
1464 object
->orig_fmt
= Mode
.Format
;
1465 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1467 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1468 * then the corresponding dimension of the client area of the hDeviceWindow
1469 * (or the focus window, if hDeviceWindow is NULL) is taken.
1470 **********************/
1472 if (pPresentationParameters
->Windowed
&&
1473 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1474 (pPresentationParameters
->BackBufferHeight
== 0) ||
1475 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1478 GetClientRect(object
->win_handle
, &Rect
);
1480 if (pPresentationParameters
->BackBufferWidth
== 0) {
1481 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1482 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1484 if (pPresentationParameters
->BackBufferHeight
== 0) {
1485 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1486 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1488 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1489 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1490 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1494 /* Put the correct figures in the presentation parameters */
1495 TRACE("Copying across presentation parameters\n");
1496 object
->presentParms
= *pPresentationParameters
;
1498 TRACE("calling rendertarget CB\n");
1499 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1501 object
->presentParms
.BackBufferWidth
,
1502 object
->presentParms
.BackBufferHeight
,
1503 object
->presentParms
.BackBufferFormat
,
1504 object
->presentParms
.MultiSampleType
,
1505 object
->presentParms
.MultiSampleQuality
,
1506 TRUE
/* Lockable */,
1507 &object
->frontBuffer
,
1508 NULL
/* pShared (always null)*/);
1509 if (SUCCEEDED(hr
)) {
1510 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1511 if(surface_type
== SURFACE_OPENGL
) {
1512 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1515 ERR("Failed to create the front buffer\n");
1519 /*********************
1520 * Windowed / Fullscreen
1521 *******************/
1524 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1525 * so we should really check to see if there is a fullscreen swapchain already
1526 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1527 **************************************/
1529 if (!pPresentationParameters
->Windowed
) {
1530 WINED3DDISPLAYMODE mode
;
1533 /* Change the display settings */
1534 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1535 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1536 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1537 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1539 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1540 displaymode_set
= TRUE
;
1544 * Create an opengl context for the display visual
1545 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1546 * use different properties after that point in time. FIXME: How to handle when requested format
1547 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1548 * it chooses is identical to the one already being used!
1549 **********************************/
1550 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1552 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1553 if(!object
->context
) {
1554 ERR("Failed to create the context array\n");
1558 object
->num_contexts
= 1;
1560 if(surface_type
== SURFACE_OPENGL
) {
1561 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1562 if (!object
->context
[0]) {
1563 ERR("Failed to create a new context\n");
1564 hr
= WINED3DERR_NOTAVAILABLE
;
1567 TRACE("Context created (HWND=%p, glContext=%p)\n",
1568 object
->win_handle
, object
->context
[0]->glCtx
);
1572 /*********************
1573 * Create the back, front and stencil buffers
1574 *******************/
1575 if(object
->presentParms
.BackBufferCount
> 0) {
1578 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1579 if(!object
->backBuffer
) {
1580 ERR("Out of memory\n");
1585 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1586 TRACE("calling rendertarget CB\n");
1587 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1589 object
->presentParms
.BackBufferWidth
,
1590 object
->presentParms
.BackBufferHeight
,
1591 object
->presentParms
.BackBufferFormat
,
1592 object
->presentParms
.MultiSampleType
,
1593 object
->presentParms
.MultiSampleQuality
,
1594 TRUE
/* Lockable */,
1595 &object
->backBuffer
[i
],
1596 NULL
/* pShared (always null)*/);
1598 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1600 ERR("Cannot create new back buffer\n");
1603 if(surface_type
== SURFACE_OPENGL
) {
1605 glDrawBuffer(GL_BACK
);
1606 checkGLcall("glDrawBuffer(GL_BACK)");
1611 object
->backBuffer
= NULL
;
1613 /* Single buffering - draw to front buffer */
1614 if(surface_type
== SURFACE_OPENGL
) {
1616 glDrawBuffer(GL_FRONT
);
1617 checkGLcall("glDrawBuffer(GL_FRONT)");
1622 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1623 if (pPresentationParameters
->EnableAutoDepthStencil
&& surface_type
== SURFACE_OPENGL
) {
1624 TRACE("Creating depth stencil buffer\n");
1625 if (This
->auto_depth_stencil_buffer
== NULL
) {
1626 hr
= D3DCB_CreateDepthStencil(This
->parent
,
1628 object
->presentParms
.BackBufferWidth
,
1629 object
->presentParms
.BackBufferHeight
,
1630 object
->presentParms
.AutoDepthStencilFormat
,
1631 object
->presentParms
.MultiSampleType
,
1632 object
->presentParms
.MultiSampleQuality
,
1633 FALSE
/* FIXME: Discard */,
1634 &This
->auto_depth_stencil_buffer
,
1635 NULL
/* pShared (always null)*/ );
1636 if (SUCCEEDED(hr
)) {
1637 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1639 ERR("Failed to create the auto depth stencil\n");
1645 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1647 TRACE("Created swapchain %p\n", object
);
1648 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, pPresentationParameters
->EnableAutoDepthStencil
);
1652 if (displaymode_set
) {
1656 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1659 /* Change the display settings */
1660 memset(&devmode
, 0, sizeof(devmode
));
1661 devmode
.dmSize
= sizeof(devmode
);
1662 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1663 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1664 devmode
.dmPelsWidth
= object
->orig_width
;
1665 devmode
.dmPelsHeight
= object
->orig_height
;
1666 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1669 if (object
->backBuffer
) {
1671 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1672 if(object
->backBuffer
[i
]) {
1673 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1674 IUnknown_Release(bufferParent
); /* once for the get parent */
1675 if (IUnknown_Release(bufferParent
) > 0) {
1676 FIXME("(%p) Something's still holding the back buffer\n",This
);
1680 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1681 object
->backBuffer
= NULL
;
1683 if(object
->context
&& object
->context
[0])
1684 DestroyContext(This
, object
->context
[0]);
1685 if(object
->frontBuffer
) {
1686 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1687 IUnknown_Release(bufferParent
); /* once for the get parent */
1688 if (IUnknown_Release(bufferParent
) > 0) {
1689 FIXME("(%p) Something's still holding the front buffer\n",This
);
1692 HeapFree(GetProcessHeap(), 0, object
);
1696 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1697 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1698 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1699 TRACE("(%p)\n", This
);
1701 return This
->NumberOfSwapChains
;
1704 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1705 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1706 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1708 if(iSwapChain
< This
->NumberOfSwapChains
) {
1709 *pSwapChain
= This
->swapchains
[iSwapChain
];
1710 IWineD3DSwapChain_AddRef(*pSwapChain
);
1711 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1714 TRACE("Swapchain out of range\n");
1716 return WINED3DERR_INVALIDCALL
;
1721 * Vertex Declaration
1723 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1724 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
1725 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1726 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1727 HRESULT hr
= WINED3D_OK
;
1729 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1730 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1732 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1734 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1736 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration
*)object
);
1737 *ppVertexDeclaration
= NULL
;
1743 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1744 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1746 unsigned int idx
, idx2
;
1747 unsigned int offset
;
1748 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1749 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1750 BOOL has_blend_idx
= has_blend
&&
1751 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1752 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1753 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1754 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1755 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1756 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1757 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1759 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1760 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1762 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1763 WINED3DVERTEXELEMENT
*elements
= NULL
;
1766 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1767 if (has_blend_idx
) num_blends
--;
1769 /* Compute declaration size */
1770 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1771 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1773 /* convert the declaration */
1774 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1778 elements
[size
-1] = end_element
;
1781 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1782 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1783 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1786 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1787 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1789 elements
[idx
].UsageIndex
= 0;
1792 if (has_blend
&& (num_blends
> 0)) {
1793 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1794 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1796 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1797 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1798 elements
[idx
].UsageIndex
= 0;
1801 if (has_blend_idx
) {
1802 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1803 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1804 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1805 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1806 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1808 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1809 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1810 elements
[idx
].UsageIndex
= 0;
1814 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1815 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1816 elements
[idx
].UsageIndex
= 0;
1820 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1821 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1822 elements
[idx
].UsageIndex
= 0;
1826 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1827 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1828 elements
[idx
].UsageIndex
= 0;
1832 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1833 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1834 elements
[idx
].UsageIndex
= 1;
1837 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1838 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1839 switch (numcoords
) {
1840 case WINED3DFVF_TEXTUREFORMAT1
:
1841 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1843 case WINED3DFVF_TEXTUREFORMAT2
:
1844 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1846 case WINED3DFVF_TEXTUREFORMAT3
:
1847 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1849 case WINED3DFVF_TEXTUREFORMAT4
:
1850 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1853 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1854 elements
[idx
].UsageIndex
= idx2
;
1858 /* Now compute offsets, and initialize the rest of the fields */
1859 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1860 elements
[idx
].Stream
= 0;
1861 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1862 elements
[idx
].Offset
= offset
;
1863 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1866 *ppVertexElements
= elements
;
1870 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1871 WINED3DVERTEXELEMENT
* elements
= NULL
;
1872 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1876 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1877 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1879 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1880 HeapFree(GetProcessHeap(), 0, elements
);
1881 if (hr
!= S_OK
) return hr
;
1886 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1887 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1888 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1889 HRESULT hr
= WINED3D_OK
;
1890 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1891 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1893 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1895 if (vertex_declaration
) {
1896 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1899 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1901 if (WINED3D_OK
!= hr
) {
1902 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1903 IWineD3DVertexShader_Release(*ppVertexShader
);
1904 return WINED3DERR_INVALIDCALL
;
1906 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1911 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1912 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1913 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1914 HRESULT hr
= WINED3D_OK
;
1916 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1917 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1918 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1919 if (WINED3D_OK
== hr
) {
1920 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1921 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1923 WARN("(%p) : Failed to create pixel shader\n", This
);
1929 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1930 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1931 IWineD3DPaletteImpl
*object
;
1933 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1935 /* Create the new object */
1936 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1938 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1939 return E_OUTOFMEMORY
;
1942 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1944 object
->Flags
= Flags
;
1945 object
->parent
= Parent
;
1946 object
->wineD3DDevice
= This
;
1947 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1949 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1952 HeapFree( GetProcessHeap(), 0, object
);
1953 return E_OUTOFMEMORY
;
1956 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1958 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1962 *Palette
= (IWineD3DPalette
*) object
;
1967 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1971 HDC dcb
= NULL
, dcs
= NULL
;
1972 WINEDDCOLORKEY colorkey
;
1974 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1977 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1978 dcb
= CreateCompatibleDC(NULL
);
1980 SelectObject(dcb
, hbm
);
1984 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1985 * couldn't be loaded
1987 memset(&bm
, 0, sizeof(bm
));
1992 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1993 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1994 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1996 ERR("Wine logo requested, but failed to create surface\n");
2001 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
2002 if(FAILED(hr
)) goto out
;
2003 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
2004 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
2006 colorkey
.dwColorSpaceLowValue
= 0;
2007 colorkey
.dwColorSpaceHighValue
= 0;
2008 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
2010 /* Fill the surface with a white color to show that wined3d is there */
2011 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2024 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
2026 /* Under DirectX you can have texture stage operations even if no texture is
2027 bound, whereas opengl will only do texture operations when a valid texture is
2028 bound. We emulate this by creating dummy textures and binding them to each
2029 texture stage, but disable all stages by default. Hence if a stage is enabled
2030 then the default texture will kick in until replaced by a SetTexture call */
2033 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2034 /* The dummy texture does not have client storage backing */
2035 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2036 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2038 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2039 GLubyte white
= 255;
2041 /* Make appropriate texture active */
2042 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2043 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2044 checkGLcall("glActiveTextureARB");
2046 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2049 /* Generate an opengl texture name */
2050 glGenTextures(1, &This
->dummyTextureName
[i
]);
2051 checkGLcall("glGenTextures");
2052 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2054 /* Generate a dummy 2d texture (not using 1d because they cause many
2055 * DRI drivers fall back to sw) */
2056 This
->stateBlock
->textureDimensions
[i
] = GL_TEXTURE_2D
;
2057 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2058 checkGLcall("glBindTexture");
2060 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2061 checkGLcall("glTexImage2D");
2063 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2064 /* Reenable because if supported it is enabled by default */
2065 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2066 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2072 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain
) {
2073 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2074 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2079 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateSwapChain
);
2080 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2081 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2083 /* TODO: Test if OpenGL is compiled in and loaded */
2085 TRACE("(%p) : Creating stateblock\n", This
);
2086 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2087 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2089 (IWineD3DStateBlock
**)&This
->stateBlock
,
2091 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2092 WARN("Failed to create stateblock\n");
2095 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2096 This
->updateStateBlock
= This
->stateBlock
;
2097 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2099 hr
= allocate_shader_constants(This
->updateStateBlock
);
2100 if (WINED3D_OK
!= hr
) {
2104 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2105 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2107 This
->NumberOfPalettes
= 1;
2108 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
2109 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
2110 ERR("Out of memory!\n");
2113 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2114 if(!This
->palettes
[0]) {
2115 ERR("Out of memory!\n");
2118 for (i
= 0; i
< 256; ++i
) {
2119 This
->palettes
[0][i
].peRed
= 0xFF;
2120 This
->palettes
[0][i
].peGreen
= 0xFF;
2121 This
->palettes
[0][i
].peBlue
= 0xFF;
2122 This
->palettes
[0][i
].peFlags
= 0xFF;
2124 This
->currentPalette
= 0;
2126 /* Initialize the texture unit mapping to a 1:1 mapping */
2127 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2128 if (state
< GL_LIMITS(fragment_samplers
)) {
2129 This
->texUnitMap
[state
] = state
;
2130 This
->rev_tex_unit_map
[state
] = state
;
2132 This
->texUnitMap
[state
] = -1;
2133 This
->rev_tex_unit_map
[state
] = -1;
2137 /* Setup the implicit swapchain */
2138 TRACE("Creating implicit swapchain\n");
2139 hr
=D3DCB_CreateSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2140 if (FAILED(hr
) || !swapchain
) {
2141 WARN("Failed to create implicit swapchain\n");
2145 This
->NumberOfSwapChains
= 1;
2146 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2147 if(!This
->swapchains
) {
2148 ERR("Out of memory!\n");
2151 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2153 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2154 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2155 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2156 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2159 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2160 This
->render_targets
[0] = swapchain
->frontBuffer
;
2161 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2163 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2164 This
->activeContext
= swapchain
->context
[0];
2165 This
->lastThread
= GetCurrentThreadId();
2167 /* Depth Stencil support */
2168 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2169 if (NULL
!= This
->stencilBufferTarget
) {
2170 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2173 hr
= This
->shader_backend
->shader_alloc_private(iface
);
2175 TRACE("Shader private data couldn't be allocated\n");
2178 hr
= This
->frag_pipe
->alloc_private(iface
);
2180 TRACE("Fragment pipeline private data couldn't be allocated\n");
2183 hr
= This
->blitter
->alloc_private(iface
);
2185 TRACE("Blitter private data couldn't be allocated\n");
2189 /* Set up some starting GL setup */
2191 /* Setup all the devices defaults */
2192 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2193 create_dummy_textures(This
);
2197 { /* Set a default viewport */
2201 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2202 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2205 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2208 /* Initialize the current view state */
2209 This
->view_ident
= 1;
2210 This
->contexts
[0]->last_was_rhw
= 0;
2211 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2212 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2214 switch(wined3d_settings
.offscreen_rendering_mode
) {
2217 This
->offscreenBuffer
= GL_BACK
;
2220 case ORM_BACKBUFFER
:
2222 if(This
->activeContext
->aux_buffers
> 0) {
2223 TRACE("Using auxilliary buffer for offscreen rendering\n");
2224 This
->offscreenBuffer
= GL_AUX0
;
2226 TRACE("Using back buffer for offscreen rendering\n");
2227 This
->offscreenBuffer
= GL_BACK
;
2232 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2235 /* Clear the screen */
2236 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2237 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2240 This
->d3d_initialized
= TRUE
;
2242 if(wined3d_settings
.logo
) {
2243 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2245 This
->highest_dirty_ps_const
= 0;
2246 This
->highest_dirty_vs_const
= 0;
2250 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2251 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2252 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2253 This
->NumberOfSwapChains
= 0;
2254 if(This
->palettes
) {
2255 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2256 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2258 This
->NumberOfPalettes
= 0;
2260 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2262 if(This
->stateBlock
) {
2263 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2264 This
->stateBlock
= NULL
;
2266 if (This
->blit_priv
) {
2267 This
->blitter
->free_private(iface
);
2269 if (This
->fragment_priv
) {
2270 This
->frag_pipe
->free_private(iface
);
2272 if (This
->shader_priv
) {
2273 This
->shader_backend
->shader_free_private(iface
);
2278 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain
) {
2279 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2280 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2283 /* Setup the implicit swapchain */
2284 TRACE("Creating implicit swapchain\n");
2285 hr
=D3DCB_CreateSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2286 if (FAILED(hr
) || !swapchain
) {
2287 WARN("Failed to create implicit swapchain\n");
2291 This
->NumberOfSwapChains
= 1;
2292 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2293 if(!This
->swapchains
) {
2294 ERR("Out of memory!\n");
2297 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2301 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2305 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2306 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2309 TRACE("(%p)\n", This
);
2311 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2313 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2314 * it was created. Thus make sure a context is active for the glDelete* calls
2316 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2318 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2320 TRACE("Deleting high order patches\n");
2321 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2322 struct list
*e1
, *e2
;
2323 struct WineD3DRectPatch
*patch
;
2324 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2325 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2326 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2330 /* Delete the palette conversion shader if it is around */
2331 if(This
->paletteConversionShader
) {
2333 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2335 This
->paletteConversionShader
= 0;
2338 /* Delete the pbuffer context if there is any */
2339 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2341 /* Delete the mouse cursor texture */
2342 if(This
->cursorTexture
) {
2344 glDeleteTextures(1, &This
->cursorTexture
);
2346 This
->cursorTexture
= 0;
2349 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2350 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2352 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2353 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2356 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2357 * private data, it might contain opengl pointers
2359 if(This
->depth_blt_texture
) {
2360 glDeleteTextures(1, &This
->depth_blt_texture
);
2361 This
->depth_blt_texture
= 0;
2363 if (This
->depth_blt_rb
) {
2364 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2365 This
->depth_blt_rb
= 0;
2366 This
->depth_blt_rb_w
= 0;
2367 This
->depth_blt_rb_h
= 0;
2370 /* Release the update stateblock */
2371 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2372 if(This
->updateStateBlock
!= This
->stateBlock
)
2373 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2375 This
->updateStateBlock
= NULL
;
2377 { /* because were not doing proper internal refcounts releasing the primary state block
2378 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2379 to set this->stateBlock = NULL; first */
2380 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2381 This
->stateBlock
= NULL
;
2383 /* Release the stateblock */
2384 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2385 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2389 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2390 This
->blitter
->free_private(iface
);
2391 This
->frag_pipe
->free_private(iface
);
2392 This
->shader_backend
->shader_free_private(iface
);
2394 /* Release the buffers (with sanity checks)*/
2395 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2396 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2397 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2398 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2400 This
->stencilBufferTarget
= NULL
;
2402 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2403 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2404 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2406 TRACE("Setting rendertarget to NULL\n");
2407 This
->render_targets
[0] = NULL
;
2409 if (This
->auto_depth_stencil_buffer
) {
2410 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2411 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2413 This
->auto_depth_stencil_buffer
= NULL
;
2416 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2417 TRACE("Releasing the implicit swapchain %d\n", i
);
2418 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2419 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2423 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2424 This
->swapchains
= NULL
;
2425 This
->NumberOfSwapChains
= 0;
2427 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2428 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2429 This
->palettes
= NULL
;
2430 This
->NumberOfPalettes
= 0;
2432 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2433 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2434 This
->render_targets
= NULL
;
2435 This
->draw_buffers
= NULL
;
2437 This
->d3d_initialized
= FALSE
;
2441 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2442 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2445 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2446 TRACE("Releasing the implicit swapchain %d\n", i
);
2447 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2448 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2452 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2453 This
->swapchains
= NULL
;
2454 This
->NumberOfSwapChains
= 0;
2458 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2459 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2460 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2462 * There is no way to deactivate thread safety once it is enabled.
2464 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2465 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2467 /*For now just store the flag(needed in case of ddraw) */
2468 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2473 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2475 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2477 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2480 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2482 /* Resize the screen even without a window:
2483 * The app could have unset it with SetCooperativeLevel, but not called
2484 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2485 * but we don't have any hwnd
2488 memset(&devmode
, 0, sizeof(devmode
));
2489 devmode
.dmSize
= sizeof(devmode
);
2490 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2491 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2492 devmode
.dmPelsWidth
= pMode
->Width
;
2493 devmode
.dmPelsHeight
= pMode
->Height
;
2495 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2496 if (pMode
->RefreshRate
!= 0) {
2497 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2500 /* Only change the mode if necessary */
2501 if( (This
->ddraw_width
== pMode
->Width
) &&
2502 (This
->ddraw_height
== pMode
->Height
) &&
2503 (This
->ddraw_format
== pMode
->Format
) &&
2504 (pMode
->RefreshRate
== 0) ) {
2508 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2509 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2510 if(devmode
.dmDisplayFrequency
!= 0) {
2511 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2512 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2513 devmode
.dmDisplayFrequency
= 0;
2514 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2516 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2517 return WINED3DERR_NOTAVAILABLE
;
2521 /* Store the new values */
2522 This
->ddraw_width
= pMode
->Width
;
2523 This
->ddraw_height
= pMode
->Height
;
2524 This
->ddraw_format
= pMode
->Format
;
2526 /* And finally clip mouse to our screen */
2527 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2528 ClipCursor(&clip_rc
);
2533 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2534 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2535 *ppD3D
= This
->wineD3D
;
2536 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2537 IWineD3D_AddRef(*ppD3D
);
2541 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2542 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2544 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2545 (This
->adapter
->TextureRam
/(1024*1024)),
2546 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2547 /* return simulated texture memory left */
2548 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2556 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2557 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2559 /* Update the current state block */
2560 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2562 if(This
->updateStateBlock
->fvf
== fvf
) {
2563 TRACE("Application is setting the old fvf over, nothing to do\n");
2567 This
->updateStateBlock
->fvf
= fvf
;
2568 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2569 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2574 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2575 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2576 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2577 *pfvf
= This
->stateBlock
->fvf
;
2582 * Get / Set Stream Source
2584 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2585 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2586 IWineD3DVertexBuffer
*oldSrc
;
2588 if (StreamNumber
>= MAX_STREAMS
) {
2589 WARN("Stream out of range %d\n", StreamNumber
);
2590 return WINED3DERR_INVALIDCALL
;
2591 } else if(OffsetInBytes
& 0x3) {
2592 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2593 return WINED3DERR_INVALIDCALL
;
2596 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2597 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2599 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2601 if(oldSrc
== pStreamData
&&
2602 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2603 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2604 TRACE("Application is setting the old values over, nothing to do\n");
2608 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2610 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2611 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2614 /* Handle recording of state blocks */
2615 if (This
->isRecordingState
) {
2616 TRACE("Recording... not performing anything\n");
2617 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2618 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2622 /* Need to do a getParent and pass the references up */
2623 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2624 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2625 so for now, just count internally */
2626 if (pStreamData
!= NULL
) {
2627 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2628 InterlockedIncrement(&vbImpl
->bindCount
);
2629 IWineD3DVertexBuffer_AddRef(pStreamData
);
2631 if (oldSrc
!= NULL
) {
2632 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2633 IWineD3DVertexBuffer_Release(oldSrc
);
2636 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2641 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2642 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2644 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2645 This
->stateBlock
->streamSource
[StreamNumber
],
2646 This
->stateBlock
->streamOffset
[StreamNumber
],
2647 This
->stateBlock
->streamStride
[StreamNumber
]);
2649 if (StreamNumber
>= MAX_STREAMS
) {
2650 WARN("Stream out of range %d\n", StreamNumber
);
2651 return WINED3DERR_INVALIDCALL
;
2653 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2654 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2656 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2659 if (*pStream
!= NULL
) {
2660 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2665 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2666 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2667 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2668 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2670 /* Verify input at least in d3d9 this is invalid*/
2671 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2672 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2673 return WINED3DERR_INVALIDCALL
;
2675 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2676 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2677 return WINED3DERR_INVALIDCALL
;
2680 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2681 return WINED3DERR_INVALIDCALL
;
2684 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2685 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2687 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2688 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2690 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2691 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2692 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2698 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2699 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2701 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2702 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2704 TRACE("(%p) : returning %d\n", This
, *Divider
);
2710 * Get / Set & Multiply Transform
2712 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2713 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2715 /* Most of this routine, comments included copied from ddraw tree initially: */
2716 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2718 /* Handle recording of state blocks */
2719 if (This
->isRecordingState
) {
2720 TRACE("Recording... not performing anything\n");
2721 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2722 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2727 * If the new matrix is the same as the current one,
2728 * we cut off any further processing. this seems to be a reasonable
2729 * optimization because as was noticed, some apps (warcraft3 for example)
2730 * tend towards setting the same matrix repeatedly for some reason.
2732 * From here on we assume that the new matrix is different, wherever it matters.
2734 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2735 TRACE("The app is setting the same matrix over again\n");
2738 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2742 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2743 where ViewMat = Camera space, WorldMat = world space.
2745 In OpenGL, camera and world space is combined into GL_MODELVIEW
2746 matrix. The Projection matrix stay projection matrix.
2749 /* Capture the times we can just ignore the change for now */
2750 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2751 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2752 /* Handled by the state manager */
2755 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2759 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2760 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2761 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2762 *pMatrix
= This
->stateBlock
->transforms
[State
];
2766 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2767 WINED3DMATRIX
*mat
= NULL
;
2770 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2771 * below means it will be recorded in a state block change, but it
2772 * works regardless where it is recorded.
2773 * If this is found to be wrong, change to StateBlock.
2775 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2776 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2778 if (State
< HIGHEST_TRANSFORMSTATE
)
2780 mat
= &This
->updateStateBlock
->transforms
[State
];
2782 FIXME("Unhandled transform state!!\n");
2785 multiply_matrix(&temp
, mat
, pMatrix
);
2787 /* Apply change via set transform - will reapply to eg. lights this way */
2788 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2794 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2795 you can reference any indexes you want as long as that number max are enabled at any
2796 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2797 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2798 but when recording, just build a chain pretty much of commands to be replayed. */
2800 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2802 PLIGHTINFOEL
*object
= NULL
;
2803 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2806 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2807 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2809 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2813 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2814 return WINED3DERR_INVALIDCALL
;
2817 switch(pLight
->Type
) {
2818 case WINED3DLIGHT_POINT
:
2819 case WINED3DLIGHT_SPOT
:
2820 case WINED3DLIGHT_PARALLELPOINT
:
2821 case WINED3DLIGHT_GLSPOT
:
2822 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2825 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2826 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2827 return WINED3DERR_INVALIDCALL
;
2831 case WINED3DLIGHT_DIRECTIONAL
:
2832 /* Ignores attenuation */
2836 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2837 return WINED3DERR_INVALIDCALL
;
2840 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2841 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2842 if(object
->OriginalIndex
== Index
) break;
2847 TRACE("Adding new light\n");
2848 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2850 ERR("Out of memory error when allocating a light\n");
2851 return E_OUTOFMEMORY
;
2853 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2854 object
->glIndex
= -1;
2855 object
->OriginalIndex
= Index
;
2856 object
->changed
= TRUE
;
2859 /* Initialize the object */
2860 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
,
2861 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2862 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2863 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2864 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2865 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2866 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2868 /* Save away the information */
2869 object
->OriginalParms
= *pLight
;
2871 switch (pLight
->Type
) {
2872 case WINED3DLIGHT_POINT
:
2874 object
->lightPosn
[0] = pLight
->Position
.x
;
2875 object
->lightPosn
[1] = pLight
->Position
.y
;
2876 object
->lightPosn
[2] = pLight
->Position
.z
;
2877 object
->lightPosn
[3] = 1.0f
;
2878 object
->cutoff
= 180.0f
;
2882 case WINED3DLIGHT_DIRECTIONAL
:
2884 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2885 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2886 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2887 object
->lightPosn
[3] = 0.0;
2888 object
->exponent
= 0.0f
;
2889 object
->cutoff
= 180.0f
;
2892 case WINED3DLIGHT_SPOT
:
2894 object
->lightPosn
[0] = pLight
->Position
.x
;
2895 object
->lightPosn
[1] = pLight
->Position
.y
;
2896 object
->lightPosn
[2] = pLight
->Position
.z
;
2897 object
->lightPosn
[3] = 1.0;
2900 object
->lightDirn
[0] = pLight
->Direction
.x
;
2901 object
->lightDirn
[1] = pLight
->Direction
.y
;
2902 object
->lightDirn
[2] = pLight
->Direction
.z
;
2903 object
->lightDirn
[3] = 1.0;
2906 * opengl-ish and d3d-ish spot lights use too different models for the
2907 * light "intensity" as a function of the angle towards the main light direction,
2908 * so we only can approximate very roughly.
2909 * however spot lights are rather rarely used in games (if ever used at all).
2910 * furthermore if still used, probably nobody pays attention to such details.
2912 if (pLight
->Falloff
== 0) {
2913 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2914 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2915 * will always be 1.0 for both of them, and we don't have to care for the
2916 * rest of the rather complex calculation
2918 object
->exponent
= 0;
2920 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2921 if (rho
< 0.0001) rho
= 0.0001f
;
2922 object
->exponent
= -0.3/log(cos(rho
/2));
2924 if (object
->exponent
> 128.0) {
2925 object
->exponent
= 128.0;
2927 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2933 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2936 /* Update the live definitions if the light is currently assigned a glIndex */
2937 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2938 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2943 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2944 PLIGHTINFOEL
*lightInfo
= NULL
;
2945 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2946 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2948 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2950 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2951 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2952 if(lightInfo
->OriginalIndex
== Index
) break;
2956 if (lightInfo
== NULL
) {
2957 TRACE("Light information requested but light not defined\n");
2958 return WINED3DERR_INVALIDCALL
;
2961 *pLight
= lightInfo
->OriginalParms
;
2966 * Get / Set Light Enable
2967 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2969 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2970 PLIGHTINFOEL
*lightInfo
= NULL
;
2971 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2972 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2974 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2976 /* Tests show true = 128...not clear why */
2977 Enable
= Enable
? 128: 0;
2979 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2980 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2981 if(lightInfo
->OriginalIndex
== Index
) break;
2984 TRACE("Found light: %p\n", lightInfo
);
2986 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2987 if (lightInfo
== NULL
) {
2989 TRACE("Light enabled requested but light not defined, so defining one!\n");
2990 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2992 /* Search for it again! Should be fairly quick as near head of list */
2993 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2994 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2995 if(lightInfo
->OriginalIndex
== Index
) break;
2998 if (lightInfo
== NULL
) {
2999 FIXME("Adding default lights has failed dismally\n");
3000 return WINED3DERR_INVALIDCALL
;
3004 lightInfo
->enabledChanged
= TRUE
;
3006 if(lightInfo
->glIndex
!= -1) {
3007 if(!This
->isRecordingState
) {
3008 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
3011 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
3012 lightInfo
->glIndex
= -1;
3014 TRACE("Light already disabled, nothing to do\n");
3016 lightInfo
->enabled
= FALSE
;
3018 lightInfo
->enabled
= TRUE
;
3019 if (lightInfo
->glIndex
!= -1) {
3021 TRACE("Nothing to do as light was enabled\n");
3024 /* Find a free gl light */
3025 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
3026 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
3027 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
3028 lightInfo
->glIndex
= i
;
3032 if(lightInfo
->glIndex
== -1) {
3033 /* Our tests show that Windows returns D3D_OK in this situation, even with
3034 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3035 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3036 * as well for those lights.
3038 * TODO: Test how this affects rendering
3040 FIXME("Too many concurrently active lights\n");
3044 /* i == lightInfo->glIndex */
3045 if(!This
->isRecordingState
) {
3046 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
3054 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
3056 PLIGHTINFOEL
*lightInfo
= NULL
;
3057 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3059 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3060 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3062 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3063 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3064 if(lightInfo
->OriginalIndex
== Index
) break;
3068 if (lightInfo
== NULL
) {
3069 TRACE("Light enabled state requested but light not defined\n");
3070 return WINED3DERR_INVALIDCALL
;
3072 /* true is 128 according to SetLightEnable */
3073 *pEnable
= lightInfo
->enabled
? 128 : 0;
3078 * Get / Set Clip Planes
3080 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3081 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3082 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3084 /* Validate Index */
3085 if (Index
>= GL_LIMITS(clipplanes
)) {
3086 TRACE("Application has requested clipplane this device doesn't support\n");
3087 return WINED3DERR_INVALIDCALL
;
3090 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
3092 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3093 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3094 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3095 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3096 TRACE("Application is setting old values over, nothing to do\n");
3100 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3101 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3102 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3103 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3105 /* Handle recording of state blocks */
3106 if (This
->isRecordingState
) {
3107 TRACE("Recording... not performing anything\n");
3111 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3116 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3118 TRACE("(%p) : for idx %d\n", This
, Index
);
3120 /* Validate Index */
3121 if (Index
>= GL_LIMITS(clipplanes
)) {
3122 TRACE("Application has requested clipplane this device doesn't support\n");
3123 return WINED3DERR_INVALIDCALL
;
3126 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3127 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3128 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3129 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3134 * Get / Set Clip Plane Status
3135 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3137 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3138 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3139 FIXME("(%p) : stub\n", This
);
3140 if (NULL
== pClipStatus
) {
3141 return WINED3DERR_INVALIDCALL
;
3143 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3144 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3148 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3149 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3150 FIXME("(%p) : stub\n", This
);
3151 if (NULL
== pClipStatus
) {
3152 return WINED3DERR_INVALIDCALL
;
3154 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3155 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3160 * Get / Set Material
3162 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3163 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3165 This
->updateStateBlock
->changed
.material
= TRUE
;
3166 This
->updateStateBlock
->material
= *pMaterial
;
3168 /* Handle recording of state blocks */
3169 if (This
->isRecordingState
) {
3170 TRACE("Recording... not performing anything\n");
3174 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3178 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3179 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3180 *pMaterial
= This
->updateStateBlock
->material
;
3181 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3182 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3183 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3184 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3185 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3186 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3187 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3188 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3189 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3197 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3198 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3199 IWineD3DIndexBuffer
*oldIdxs
;
3201 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3202 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3204 This
->updateStateBlock
->changed
.indices
= TRUE
;
3205 This
->updateStateBlock
->pIndexData
= pIndexData
;
3207 /* Handle recording of state blocks */
3208 if (This
->isRecordingState
) {
3209 TRACE("Recording... not performing anything\n");
3210 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3211 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3215 if(oldIdxs
!= pIndexData
) {
3216 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3217 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3218 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3223 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3224 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3226 *ppIndexData
= This
->stateBlock
->pIndexData
;
3228 /* up ref count on ppindexdata */
3230 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3231 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3233 TRACE("(%p) No index data set\n", This
);
3235 TRACE("Returning %p\n", *ppIndexData
);
3240 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3241 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3242 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3243 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3245 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3246 TRACE("Application is setting the old value over, nothing to do\n");
3250 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3252 if (This
->isRecordingState
) {
3253 TRACE("Recording... not performing anything\n");
3256 /* The base vertex index affects the stream sources */
3257 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3261 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3262 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3263 TRACE("(%p) : base_index %p\n", This
, base_index
);
3265 *base_index
= This
->stateBlock
->baseVertexIndex
;
3267 TRACE("Returning %u\n", *base_index
);
3273 * Get / Set Viewports
3275 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3278 TRACE("(%p)\n", This
);
3279 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3280 This
->updateStateBlock
->viewport
= *pViewport
;
3282 /* Handle recording of state blocks */
3283 if (This
->isRecordingState
) {
3284 TRACE("Recording... not performing anything\n");
3288 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3289 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3291 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3296 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3297 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3298 TRACE("(%p)\n", This
);
3299 *pViewport
= This
->stateBlock
->viewport
;
3304 * Get / Set Render States
3305 * TODO: Verify against dx9 definitions
3307 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3309 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3310 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3312 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3314 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3315 This
->updateStateBlock
->renderState
[State
] = Value
;
3317 /* Handle recording of state blocks */
3318 if (This
->isRecordingState
) {
3319 TRACE("Recording... not performing anything\n");
3323 /* Compared here and not before the assignment to allow proper stateblock recording */
3324 if(Value
== oldValue
) {
3325 TRACE("Application is setting the old value over, nothing to do\n");
3327 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3333 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3334 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3335 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3336 *pValue
= This
->stateBlock
->renderState
[State
];
3341 * Get / Set Sampler States
3342 * TODO: Verify against dx9 definitions
3345 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3346 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3349 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3350 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3352 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3353 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3356 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3357 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3358 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3361 * SetSampler is designed to allow for more than the standard up to 8 textures
3362 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3363 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3365 * http://developer.nvidia.com/object/General_FAQ.html#t6
3367 * There are two new settings for GForce
3369 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3370 * and the texture one:
3371 * GL_MAX_TEXTURE_COORDS_ARB.
3372 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3375 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3376 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3377 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3379 /* Handle recording of state blocks */
3380 if (This
->isRecordingState
) {
3381 TRACE("Recording... not performing anything\n");
3385 if(oldValue
== Value
) {
3386 TRACE("Application is setting the old value over, nothing to do\n");
3390 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3395 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3396 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3398 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3399 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3401 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3402 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3405 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3406 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3407 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3409 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3410 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3415 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3416 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3418 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3419 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3420 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3423 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3425 if(This
->isRecordingState
) {
3426 TRACE("Recording... not performing anything\n");
3430 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3435 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3436 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3438 *pRect
= This
->updateStateBlock
->scissorRect
;
3439 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3443 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3444 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3445 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3447 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3449 This
->updateStateBlock
->vertexDecl
= pDecl
;
3450 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3452 if (This
->isRecordingState
) {
3453 TRACE("Recording... not performing anything\n");
3455 } else if(pDecl
== oldDecl
) {
3456 /* Checked after the assignment to allow proper stateblock recording */
3457 TRACE("Application is setting the old declaration over, nothing to do\n");
3461 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3465 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3466 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3468 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3470 *ppDecl
= This
->stateBlock
->vertexDecl
;
3471 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3475 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3476 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3477 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3479 This
->updateStateBlock
->vertexShader
= pShader
;
3480 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3482 if (This
->isRecordingState
) {
3483 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3484 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3485 TRACE("Recording... not performing anything\n");
3487 } else if(oldShader
== pShader
) {
3488 /* Checked here to allow proper stateblock recording */
3489 TRACE("App is setting the old shader over, nothing to do\n");
3493 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3494 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3495 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3497 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3502 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3503 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3505 if (NULL
== ppShader
) {
3506 return WINED3DERR_INVALIDCALL
;
3508 *ppShader
= This
->stateBlock
->vertexShader
;
3509 if( NULL
!= *ppShader
)
3510 IWineD3DVertexShader_AddRef(*ppShader
);
3512 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3516 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3517 IWineD3DDevice
*iface
,
3519 CONST BOOL
*srcData
,
3522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3523 int i
, cnt
= min(count
, MAX_CONST_B
- 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
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3532 for (i
= 0; i
< cnt
; i
++)
3533 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3535 for (i
= start
; i
< cnt
+ start
; ++i
) {
3536 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3539 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3544 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3545 IWineD3DDevice
*iface
,
3550 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3551 int cnt
= min(count
, MAX_CONST_B
- start
);
3553 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3554 iface
, dstData
, start
, count
);
3556 if (dstData
== NULL
|| cnt
< 0)
3557 return WINED3DERR_INVALIDCALL
;
3559 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3563 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3564 IWineD3DDevice
*iface
,
3569 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3570 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3572 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3573 iface
, srcData
, start
, count
);
3575 if (srcData
== NULL
|| cnt
< 0)
3576 return WINED3DERR_INVALIDCALL
;
3578 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3579 for (i
= 0; i
< cnt
; i
++)
3580 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3581 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3583 for (i
= start
; i
< cnt
+ start
; ++i
) {
3584 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3587 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3592 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3593 IWineD3DDevice
*iface
,
3598 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3599 int cnt
= min(count
, MAX_CONST_I
- start
);
3601 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3602 iface
, dstData
, start
, count
);
3604 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3605 return WINED3DERR_INVALIDCALL
;
3607 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3611 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3612 IWineD3DDevice
*iface
,
3614 CONST
float *srcData
,
3617 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3620 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3621 iface
, srcData
, start
, count
);
3623 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3624 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3625 return WINED3DERR_INVALIDCALL
;
3627 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3629 for (i
= 0; i
< count
; i
++)
3630 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3631 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3634 for (i
= start
; i
< count
+ start
; ++i
) {
3635 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3636 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3637 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3638 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3639 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3641 ptr
->idx
[ptr
->count
++] = i
;
3642 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3646 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3651 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3652 IWineD3DDevice
*iface
,
3654 CONST
float *srcData
,
3657 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3660 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3661 iface
, srcData
, start
, count
);
3663 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3664 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3665 return WINED3DERR_INVALIDCALL
;
3667 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3669 for (i
= 0; i
< count
; i
++)
3670 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3671 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3674 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3675 * context. On a context switch the old context will be fully dirtified
3677 memset(This
->activeContext
->vshader_const_dirty
+ start
, 1,
3678 sizeof(*This
->activeContext
->vshader_const_dirty
) * count
);
3679 This
->highest_dirty_vs_const
= max(This
->highest_dirty_vs_const
, start
+count
+1);
3681 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3686 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3687 IWineD3DDevice
*iface
,
3692 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3693 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3695 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3696 iface
, dstData
, start
, count
);
3698 if (dstData
== NULL
|| cnt
< 0)
3699 return WINED3DERR_INVALIDCALL
;
3701 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3705 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3707 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3708 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3712 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3713 int i
= This
->rev_tex_unit_map
[unit
];
3714 int j
= This
->texUnitMap
[stage
];
3716 This
->texUnitMap
[stage
] = unit
;
3717 if (i
!= -1 && i
!= stage
) {
3718 This
->texUnitMap
[i
] = -1;
3721 This
->rev_tex_unit_map
[unit
] = stage
;
3722 if (j
!= -1 && j
!= unit
) {
3723 This
->rev_tex_unit_map
[j
] = -1;
3727 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3730 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3731 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3732 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3733 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3734 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3735 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3736 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3737 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3738 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3740 if (color_op
== WINED3DTOP_DISABLE
) {
3741 /* Not used, and disable higher stages */
3742 while (i
< MAX_TEXTURES
) {
3743 This
->fixed_function_usage_map
[i
] = FALSE
;
3749 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3750 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3751 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3752 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3753 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3754 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3755 This
->fixed_function_usage_map
[i
] = TRUE
;
3757 This
->fixed_function_usage_map
[i
] = FALSE
;
3760 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3761 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3766 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3769 device_update_fixed_function_usage_map(This
);
3771 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3772 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3773 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3774 if (!This
->fixed_function_usage_map
[i
]) continue;
3776 if (This
->texUnitMap
[i
] != i
) {
3777 device_map_stage(This
, i
, i
);
3778 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3779 markTextureStagesDirty(This
, i
);
3785 /* Now work out the mapping */
3787 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3788 if (!This
->fixed_function_usage_map
[i
]) continue;
3790 if (This
->texUnitMap
[i
] != tex
) {
3791 device_map_stage(This
, i
, tex
);
3792 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3793 markTextureStagesDirty(This
, i
);
3800 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3801 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3804 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3805 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3806 device_map_stage(This
, i
, i
);
3807 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3808 if (i
< MAX_TEXTURES
) {
3809 markTextureStagesDirty(This
, i
);
3815 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3816 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3818 if (current_mapping
== -1) {
3819 /* Not currently used */
3823 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3824 /* Used by a fragment sampler */
3826 if (!pshader_sampler_tokens
) {
3827 /* No pixel shader, check fixed function */
3828 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3831 /* Pixel shader, check the shader's sampler map */
3832 return !pshader_sampler_tokens
[current_mapping
];
3835 /* Used by a vertex sampler */
3836 return !vshader_sampler_tokens
[current_mapping
];
3839 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3840 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3841 DWORD
*pshader_sampler_tokens
= NULL
;
3842 int start
= GL_LIMITS(combined_samplers
) - 1;
3846 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3848 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3849 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3850 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3853 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3854 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3855 if (vshader_sampler_tokens
[i
]) {
3856 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3857 /* Already mapped somewhere */
3861 while (start
>= 0) {
3862 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3863 device_map_stage(This
, vsampler_idx
, start
);
3864 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3876 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3877 BOOL vs
= use_vs(This
);
3878 BOOL ps
= use_ps(This
);
3881 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3882 * that would be really messy and require shader recompilation
3883 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3884 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3887 device_map_psamplers(This
);
3889 device_map_fixed_function_samplers(This
);
3893 device_map_vsamplers(This
, ps
);
3897 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3898 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3899 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3900 This
->updateStateBlock
->pixelShader
= pShader
;
3901 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3903 /* Handle recording of state blocks */
3904 if (This
->isRecordingState
) {
3905 TRACE("Recording... not performing anything\n");
3908 if (This
->isRecordingState
) {
3909 TRACE("Recording... not performing anything\n");
3910 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3911 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3915 if(pShader
== oldShader
) {
3916 TRACE("App is setting the old pixel shader over, nothing to do\n");
3920 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3921 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3923 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3924 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3929 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3930 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3932 if (NULL
== ppShader
) {
3933 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3934 return WINED3DERR_INVALIDCALL
;
3937 *ppShader
= This
->stateBlock
->pixelShader
;
3938 if (NULL
!= *ppShader
) {
3939 IWineD3DPixelShader_AddRef(*ppShader
);
3941 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3945 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3946 IWineD3DDevice
*iface
,
3948 CONST BOOL
*srcData
,
3951 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3952 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3954 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3955 iface
, srcData
, start
, count
);
3957 if (srcData
== NULL
|| cnt
< 0)
3958 return WINED3DERR_INVALIDCALL
;
3960 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3961 for (i
= 0; i
< cnt
; i
++)
3962 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3964 for (i
= start
; i
< cnt
+ start
; ++i
) {
3965 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3968 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3973 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3974 IWineD3DDevice
*iface
,
3979 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3980 int cnt
= min(count
, MAX_CONST_B
- start
);
3982 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3983 iface
, dstData
, start
, count
);
3985 if (dstData
== NULL
|| cnt
< 0)
3986 return WINED3DERR_INVALIDCALL
;
3988 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3992 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3993 IWineD3DDevice
*iface
,
3998 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3999 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
4001 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4002 iface
, srcData
, start
, count
);
4004 if (srcData
== NULL
|| cnt
< 0)
4005 return WINED3DERR_INVALIDCALL
;
4007 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
4008 for (i
= 0; i
< cnt
; i
++)
4009 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
4010 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4012 for (i
= start
; i
< cnt
+ start
; ++i
) {
4013 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
4016 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4021 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
4022 IWineD3DDevice
*iface
,
4027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4028 int cnt
= min(count
, MAX_CONST_I
- start
);
4030 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4031 iface
, dstData
, start
, count
);
4033 if (dstData
== NULL
|| cnt
< 0)
4034 return WINED3DERR_INVALIDCALL
;
4036 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
4040 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
4041 IWineD3DDevice
*iface
,
4043 CONST
float *srcData
,
4046 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4049 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4050 iface
, srcData
, start
, count
);
4052 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4053 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4054 return WINED3DERR_INVALIDCALL
;
4056 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4058 for (i
= 0; i
< count
; i
++)
4059 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4060 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4063 for (i
= start
; i
< count
+ start
; ++i
) {
4064 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
4065 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
4066 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
4067 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
4068 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
4070 ptr
->idx
[ptr
->count
++] = i
;
4071 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
4075 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4080 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4081 IWineD3DDevice
*iface
,
4083 CONST
float *srcData
,
4086 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4089 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4090 iface
, srcData
, start
, count
);
4092 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4093 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4094 return WINED3DERR_INVALIDCALL
;
4096 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4098 for (i
= 0; i
< count
; i
++)
4099 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4100 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4103 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4104 * context. On a context switch the old context will be fully dirtified
4106 memset(This
->activeContext
->pshader_const_dirty
+ start
, 1,
4107 sizeof(*This
->activeContext
->pshader_const_dirty
) * count
);
4108 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, start
+count
+1);
4110 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4115 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
4116 IWineD3DDevice
*iface
,
4121 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4122 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
4124 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4125 iface
, dstData
, start
, count
);
4127 if (dstData
== NULL
|| cnt
< 0)
4128 return WINED3DERR_INVALIDCALL
;
4130 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4134 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4136 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
4137 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4139 DWORD DestFVF
= dest
->fvf
;
4141 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4145 if (lpStrideData
->u
.s
.normal
.lpData
) {
4146 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4149 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
4150 ERR("Source has no position mask\n");
4151 return WINED3DERR_INVALIDCALL
;
4154 /* We might access VBOs from this code, so hold the lock */
4157 if (dest
->resource
.allocatedMemory
== NULL
) {
4158 /* This may happen if we do direct locking into a vbo. Unlikely,
4159 * but theoretically possible(ddraw processvertices test)
4161 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4162 if(!dest
->resource
.allocatedMemory
) {
4164 ERR("Out of memory\n");
4165 return E_OUTOFMEMORY
;
4169 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4170 checkGLcall("glBindBufferARB");
4171 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4173 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4175 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4176 checkGLcall("glUnmapBufferARB");
4180 /* Get a pointer into the destination vbo(create one if none exists) and
4181 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4183 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
4184 dest
->Flags
|= VBFLAG_CREATEVBO
;
4185 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer
*) dest
);
4189 unsigned char extrabytes
= 0;
4190 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4191 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4192 * this may write 4 extra bytes beyond the area that should be written
4194 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4195 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4196 if(!dest_conv_addr
) {
4197 ERR("Out of memory\n");
4198 /* Continue without storing converted vertices */
4200 dest_conv
= dest_conv_addr
;
4204 * a) WINED3DRS_CLIPPING is enabled
4205 * b) WINED3DVOP_CLIP is passed
4207 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4208 static BOOL warned
= FALSE
;
4210 * The clipping code is not quite correct. Some things need
4211 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4212 * so disable clipping for now.
4213 * (The graphics in Half-Life are broken, and my processvertices
4214 * test crashes with IDirect3DDevice3)
4220 FIXME("Clipping is broken and disabled for now\n");
4222 } else doClip
= FALSE
;
4223 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4225 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4228 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4229 WINED3DTS_PROJECTION
,
4231 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4232 WINED3DTS_WORLDMATRIX(0),
4235 TRACE("View mat:\n");
4236 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
);
4237 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
);
4238 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
);
4239 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
);
4241 TRACE("Proj mat:\n");
4242 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
);
4243 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
);
4244 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
);
4245 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
);
4247 TRACE("World mat:\n");
4248 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
);
4249 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
);
4250 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
);
4251 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
);
4253 /* Get the viewport */
4254 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4255 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4256 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4258 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4259 multiply_matrix(&mat
,&proj_mat
,&mat
);
4261 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4263 for (i
= 0; i
< dwCount
; i
+= 1) {
4264 unsigned int tex_index
;
4266 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4267 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4268 /* The position first */
4270 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4272 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4274 /* Multiplication with world, view and projection matrix */
4275 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
);
4276 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
);
4277 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
);
4278 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
);
4280 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4282 /* WARNING: The following things are taken from d3d7 and were not yet checked
4283 * against d3d8 or d3d9!
4286 /* Clipping conditions: From msdn
4288 * A vertex is clipped if it does not match the following requirements
4292 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4294 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4295 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4300 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4301 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4304 /* "Normal" viewport transformation (not clipped)
4305 * 1) The values are divided by rhw
4306 * 2) The y axis is negative, so multiply it with -1
4307 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4308 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4309 * 4) Multiply x with Width/2 and add Width/2
4310 * 5) The same for the height
4311 * 6) Add the viewpoint X and Y to the 2D coordinates and
4312 * The minimum Z value to z
4313 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4315 * Well, basically it's simply a linear transformation into viewport
4327 z
*= vp
.MaxZ
- vp
.MinZ
;
4329 x
+= vp
.Width
/ 2 + vp
.X
;
4330 y
+= vp
.Height
/ 2 + vp
.Y
;
4335 /* That vertex got clipped
4336 * Contrary to OpenGL it is not dropped completely, it just
4337 * undergoes a different calculation.
4339 TRACE("Vertex got clipped\n");
4346 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4347 * outside of the main vertex buffer memory. That needs some more
4352 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4355 ( (float *) dest_ptr
)[0] = x
;
4356 ( (float *) dest_ptr
)[1] = y
;
4357 ( (float *) dest_ptr
)[2] = z
;
4358 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4360 dest_ptr
+= 3 * sizeof(float);
4362 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4363 dest_ptr
+= sizeof(float);
4368 ( (float *) dest_conv
)[0] = x
* w
;
4369 ( (float *) dest_conv
)[1] = y
* w
;
4370 ( (float *) dest_conv
)[2] = z
* w
;
4371 ( (float *) dest_conv
)[3] = w
;
4373 dest_conv
+= 3 * sizeof(float);
4375 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4376 dest_conv
+= sizeof(float);
4380 if (DestFVF
& WINED3DFVF_PSIZE
) {
4381 dest_ptr
+= sizeof(DWORD
);
4382 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4384 if (DestFVF
& WINED3DFVF_NORMAL
) {
4386 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4387 /* AFAIK this should go into the lighting information */
4388 FIXME("Didn't expect the destination to have a normal\n");
4389 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4391 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4395 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4397 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4399 static BOOL warned
= FALSE
;
4402 ERR("No diffuse color in source, but destination has one\n");
4406 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4407 dest_ptr
+= sizeof(DWORD
);
4410 *( (DWORD
*) dest_conv
) = 0xffffffff;
4411 dest_conv
+= sizeof(DWORD
);
4415 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4417 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4418 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4419 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4420 dest_conv
+= sizeof(DWORD
);
4425 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4426 /* What's the color value in the feedback buffer? */
4428 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4430 static BOOL warned
= FALSE
;
4433 ERR("No specular color in source, but destination has one\n");
4437 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4438 dest_ptr
+= sizeof(DWORD
);
4441 *( (DWORD
*) dest_conv
) = 0xFF000000;
4442 dest_conv
+= sizeof(DWORD
);
4446 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4448 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4449 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4450 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4451 dest_conv
+= sizeof(DWORD
);
4456 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4458 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4459 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4461 ERR("No source texture, but destination requests one\n");
4462 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4463 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4466 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4468 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4475 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4476 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4477 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4478 dwCount
* get_flexible_vertex_size(DestFVF
),
4480 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4481 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4488 #undef copy_and_next
4490 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4491 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4492 WineDirect3DVertexStridedData strided
;
4493 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4494 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4497 ERR("Output vertex declaration not implemented yet\n");
4500 /* Need any context to write to the vbo. */
4501 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4503 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4504 * control the streamIsUP flag, thus restore it afterwards.
4506 This
->stateBlock
->streamIsUP
= FALSE
;
4507 memset(&strided
, 0, sizeof(strided
));
4508 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4509 This
->stateBlock
->streamIsUP
= streamWasUP
;
4511 if(vbo
|| SrcStartIndex
) {
4513 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4514 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4516 * Also get the start index in, but only loop over all elements if there's something to add at all.
4518 #define FIXSRC(type) \
4519 if(strided.u.s.type.VBO) { \
4520 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4521 strided.u.s.type.VBO = 0; \
4522 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4524 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4528 if(strided.u.s.type.lpData) { \
4529 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4532 FIXSRC(blendWeights
);
4533 FIXSRC(blendMatrixIndices
);
4538 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4539 FIXSRC(texCoords
[i
]);
4552 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4556 * Get / Set Texture Stage States
4557 * TODO: Verify against dx9 definitions
4559 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4560 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4561 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4563 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4565 if (Stage
>= MAX_TEXTURES
) {
4566 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4570 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4571 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4573 if (This
->isRecordingState
) {
4574 TRACE("Recording... not performing anything\n");
4578 /* Checked after the assignments to allow proper stateblock recording */
4579 if(oldValue
== Value
) {
4580 TRACE("App is setting the old value over, nothing to do\n");
4584 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4585 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4586 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4587 * Changes in other states are important on disabled stages too
4592 if(Type
== WINED3DTSS_COLOROP
) {
4595 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4596 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4597 * they have to be disabled
4599 * The current stage is dirtified below.
4601 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4602 TRACE("Additionally dirtifying stage %d\n", i
);
4603 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4605 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4606 TRACE("New lowest disabled: %d\n", Stage
);
4607 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4608 /* Previously disabled stage enabled. Stages above it may need enabling
4609 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4610 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4612 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4615 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4616 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4619 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4620 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4622 This
->stateBlock
->lowest_disabled_stage
= i
;
4623 TRACE("New lowest disabled: %d\n", i
);
4627 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4632 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4633 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4634 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4635 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4642 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4643 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4644 IWineD3DBaseTexture
*oldTexture
;
4646 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4648 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4649 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4652 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4653 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4654 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4657 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4659 if(pTexture
!= NULL
) {
4660 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4662 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4663 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4664 return WINED3DERR_INVALIDCALL
;
4666 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4669 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4670 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4672 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4673 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4674 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4676 /* Handle recording of state blocks */
4677 if (This
->isRecordingState
) {
4678 TRACE("Recording... not performing anything\n");
4682 if(oldTexture
== pTexture
) {
4683 TRACE("App is setting the same texture again, nothing to do\n");
4687 /** NOTE: MSDN says that setTexture increases the reference count,
4688 * and that the application must set the texture back to null (or have a leaky application),
4689 * This means we should pass the refcount up to the parent
4690 *******************************/
4691 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4692 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4693 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4695 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4696 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4697 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4698 * so the COLOROP and ALPHAOP have to be dirtified.
4700 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4701 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4703 if(bindCount
== 1) {
4704 new->baseTexture
.sampler
= Stage
;
4706 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4710 if (NULL
!= oldTexture
) {
4711 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4712 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4714 IWineD3DBaseTexture_Release(oldTexture
);
4715 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4716 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4717 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4720 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4722 /* Have to do a search for the other sampler(s) where the texture is bound to
4723 * Shouldn't happen as long as apps bind a texture only to one stage
4725 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4726 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4727 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4728 old
->baseTexture
.sampler
= i
;
4735 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4740 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4741 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4743 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4745 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4746 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4749 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4750 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4751 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4754 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4756 IWineD3DBaseTexture_AddRef(*ppTexture
);
4758 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4766 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4767 IWineD3DSurface
**ppBackBuffer
) {
4768 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4769 IWineD3DSwapChain
*swapChain
;
4772 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4774 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4775 if (hr
== WINED3D_OK
) {
4776 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4777 IWineD3DSwapChain_Release(swapChain
);
4779 *ppBackBuffer
= NULL
;
4784 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4785 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4786 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4787 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4790 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4791 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4792 IWineD3DSwapChain
*swapChain
;
4795 if(iSwapChain
> 0) {
4796 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4797 if (hr
== WINED3D_OK
) {
4798 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4799 IWineD3DSwapChain_Release(swapChain
);
4801 FIXME("(%p) Error getting display mode\n", This
);
4804 /* Don't read the real display mode,
4805 but return the stored mode instead. X11 can't change the color
4806 depth, and some apps are pretty angry if they SetDisplayMode from
4807 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4809 Also don't relay to the swapchain because with ddraw it's possible
4810 that there isn't a swapchain at all */
4811 pMode
->Width
= This
->ddraw_width
;
4812 pMode
->Height
= This
->ddraw_height
;
4813 pMode
->Format
= This
->ddraw_format
;
4814 pMode
->RefreshRate
= 0;
4822 * Stateblock related functions
4825 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4826 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4827 IWineD3DStateBlockImpl
*object
;
4828 HRESULT temp_result
;
4831 TRACE("(%p)\n", This
);
4833 if (This
->isRecordingState
) {
4834 return WINED3DERR_INVALIDCALL
;
4837 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4838 if (NULL
== object
) {
4839 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4840 return E_OUTOFMEMORY
;
4842 TRACE("(%p) created object %p\n", This
, object
);
4843 object
->wineD3DDevice
= This
;
4844 /** FIXME: object->parent = parent; **/
4845 object
->parent
= NULL
;
4846 object
->blockType
= WINED3DSBT_RECORDED
;
4848 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4850 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4851 list_init(&object
->lightMap
[i
]);
4854 temp_result
= allocate_shader_constants(object
);
4855 if (WINED3D_OK
!= temp_result
)
4858 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4859 This
->updateStateBlock
= object
;
4860 This
->isRecordingState
= TRUE
;
4862 TRACE("(%p) recording stateblock %p\n",This
, object
);
4866 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4867 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4869 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4871 if (!This
->isRecordingState
) {
4872 FIXME("(%p) not recording! returning error\n", This
);
4873 *ppStateBlock
= NULL
;
4874 return WINED3DERR_INVALIDCALL
;
4877 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4878 if(object
->changed
.renderState
[i
]) {
4879 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4880 object
->num_contained_render_states
++;
4883 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4884 if(object
->changed
.transform
[i
]) {
4885 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4886 object
->num_contained_transform_states
++;
4889 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4890 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4891 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4892 object
->num_contained_vs_consts_f
++;
4895 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4896 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4897 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4898 object
->num_contained_vs_consts_i
++;
4901 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4902 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4903 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4904 object
->num_contained_vs_consts_b
++;
4907 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4908 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4909 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4910 object
->num_contained_ps_consts_i
++;
4913 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4914 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4915 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4916 object
->num_contained_ps_consts_b
++;
4919 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4920 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4921 if(object
->changed
.textureState
[i
][j
]) {
4922 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4923 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4924 object
->num_contained_tss_states
++;
4928 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4929 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4930 if(object
->changed
.samplerState
[i
][j
]) {
4931 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4932 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4933 object
->num_contained_sampler_states
++;
4938 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4939 This
->isRecordingState
= FALSE
;
4940 This
->updateStateBlock
= This
->stateBlock
;
4941 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4942 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4943 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4948 * Scene related functions
4950 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4951 /* At the moment we have no need for any functionality at the beginning
4953 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4954 TRACE("(%p)\n", This
);
4957 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4958 return WINED3DERR_INVALIDCALL
;
4960 This
->inScene
= TRUE
;
4964 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4965 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4966 TRACE("(%p)\n", This
);
4968 if(!This
->inScene
) {
4969 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4970 return WINED3DERR_INVALIDCALL
;
4973 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4974 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4976 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4980 This
->inScene
= FALSE
;
4984 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4985 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4986 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4987 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4988 IWineD3DSwapChain
*swapChain
= NULL
;
4990 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4992 TRACE("(%p) Presenting the frame\n", This
);
4994 for(i
= 0 ; i
< swapchains
; i
++) {
4996 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4997 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4998 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4999 IWineD3DSwapChain_Release(swapChain
);
5005 /* Not called from the VTable (internal subroutine) */
5006 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
5007 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
5008 float Z
, DWORD Stencil
) {
5009 GLbitfield glMask
= 0;
5011 WINED3DRECT curRect
;
5013 WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
5014 UINT drawable_width
, drawable_height
;
5015 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
5016 IWineD3DSwapChainImpl
*swapchain
= NULL
;
5018 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5019 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5020 * for the cleared parts, and the untouched parts.
5022 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5023 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5024 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5025 * checking all this if the dest surface is in the drawable anyway.
5027 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
5029 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
5030 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
5031 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5034 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5035 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5036 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
5037 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
5038 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5041 if(Count
> 0 && pRects
&& (
5042 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5043 pRects
[0].x2
< target
->currentDesc
.Width
||
5044 pRects
[0].y2
< target
->currentDesc
.Height
)) {
5045 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5052 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
5054 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
5057 /* Only set the values up once, as they are not changing */
5058 if (Flags
& WINED3DCLEAR_STENCIL
) {
5059 glClearStencil(Stencil
);
5060 checkGLcall("glClearStencil");
5061 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
5062 glStencilMask(0xFFFFFFFF);
5065 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5066 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5067 glDepthMask(GL_TRUE
);
5069 checkGLcall("glClearDepth");
5070 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
5071 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
5073 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
5074 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
5075 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5077 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5078 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5079 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
5080 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
5081 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5083 else if (Count
> 0 && pRects
&& (
5084 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5085 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
5086 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
5087 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5091 if (Flags
& WINED3DCLEAR_TARGET
) {
5092 TRACE("Clearing screen with glClear to color %x\n", Color
);
5093 glClearColor(D3DCOLOR_R(Color
),
5097 checkGLcall("glClearColor");
5099 /* Clear ALL colors! */
5100 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5101 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
5104 vp_rect
.left
= vp
->X
;
5105 vp_rect
.top
= vp
->Y
;
5106 vp_rect
.right
= vp
->X
+ vp
->Width
;
5107 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5108 if (!(Count
> 0 && pRects
)) {
5109 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5110 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5112 if(This
->render_offscreen
) {
5113 glScissor(vp_rect
.left
, vp_rect
.top
,
5114 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5116 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5117 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5119 checkGLcall("glScissor");
5121 checkGLcall("glClear");
5123 /* Now process each rect in turn */
5124 for (i
= 0; i
< Count
; i
++) {
5125 /* Note gl uses lower left, width/height */
5126 IntersectRect((RECT
*) &curRect
, &vp_rect
, (RECT
*) &pRects
[i
]);
5127 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5128 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5130 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5131 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5132 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5133 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5135 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5136 * The rectangle is not cleared, no error is returned, but further rectanlges are
5137 * still cleared if they are valid
5139 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5140 TRACE("Rectangle with negative dimensions, ignoring\n");
5144 if(This
->render_offscreen
) {
5145 glScissor(curRect
.x1
, curRect
.y1
,
5146 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5148 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5149 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5151 checkGLcall("glScissor");
5154 checkGLcall("glClear");
5158 /* Restore the old values (why..?) */
5159 if (Flags
& WINED3DCLEAR_STENCIL
) {
5160 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5162 if (Flags
& WINED3DCLEAR_TARGET
) {
5163 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5164 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5165 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5166 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5167 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5169 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5170 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5172 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5174 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5175 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5176 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5177 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5182 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
5183 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
5186 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5192 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5193 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5194 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5195 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5197 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5198 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5200 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5201 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5202 /* TODO: What about depth stencil buffers without stencil bits? */
5203 return WINED3DERR_INVALIDCALL
;
5206 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5212 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
5213 UINT PrimitiveCount
) {
5215 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5217 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
5218 debug_d3dprimitivetype(PrimitiveType
),
5219 StartVertex
, PrimitiveCount
);
5221 if(!This
->stateBlock
->vertexDecl
) {
5222 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5223 return WINED3DERR_INVALIDCALL
;
5226 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5227 if(This
->stateBlock
->streamIsUP
) {
5228 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5229 This
->stateBlock
->streamIsUP
= FALSE
;
5232 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5233 This
->stateBlock
->loadBaseVertexIndex
= 0;
5234 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5236 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5237 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
5238 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5242 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5243 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5244 WINED3DPRIMITIVETYPE PrimitiveType
,
5245 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
5247 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5249 IWineD3DIndexBuffer
*pIB
;
5250 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
5253 pIB
= This
->stateBlock
->pIndexData
;
5255 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5256 * without an index buffer set. (The first time at least...)
5257 * D3D8 simply dies, but I doubt it can do much harm to return
5258 * D3DERR_INVALIDCALL there as well. */
5259 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5260 return WINED3DERR_INVALIDCALL
;
5263 if(!This
->stateBlock
->vertexDecl
) {
5264 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5265 return WINED3DERR_INVALIDCALL
;
5268 if(This
->stateBlock
->streamIsUP
) {
5269 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5270 This
->stateBlock
->streamIsUP
= FALSE
;
5272 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5274 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5275 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5276 minIndex
, NumVertices
, startIndex
, primCount
);
5278 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5279 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5285 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5286 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5287 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5290 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5291 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5296 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5297 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5298 UINT VertexStreamZeroStride
) {
5299 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5300 IWineD3DVertexBuffer
*vb
;
5302 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5303 debug_d3dprimitivetype(PrimitiveType
),
5304 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5306 if(!This
->stateBlock
->vertexDecl
) {
5307 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5308 return WINED3DERR_INVALIDCALL
;
5311 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5312 vb
= This
->stateBlock
->streamSource
[0];
5313 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5314 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5315 This
->stateBlock
->streamOffset
[0] = 0;
5316 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5317 This
->stateBlock
->streamIsUP
= TRUE
;
5318 This
->stateBlock
->loadBaseVertexIndex
= 0;
5320 /* TODO: Only mark dirty if drawing from a different UP address */
5321 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5323 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5324 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5326 /* MSDN specifies stream zero settings must be set to NULL */
5327 This
->stateBlock
->streamStride
[0] = 0;
5328 This
->stateBlock
->streamSource
[0] = NULL
;
5330 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5331 * the new stream sources or use UP drawing again
5336 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5337 UINT MinVertexIndex
, UINT NumVertices
,
5338 UINT PrimitiveCount
, CONST
void* pIndexData
,
5339 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5340 UINT VertexStreamZeroStride
) {
5342 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5343 IWineD3DVertexBuffer
*vb
;
5344 IWineD3DIndexBuffer
*ib
;
5346 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5347 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5348 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5349 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5351 if(!This
->stateBlock
->vertexDecl
) {
5352 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5353 return WINED3DERR_INVALIDCALL
;
5356 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5362 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5363 vb
= This
->stateBlock
->streamSource
[0];
5364 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5365 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5366 This
->stateBlock
->streamIsUP
= TRUE
;
5367 This
->stateBlock
->streamOffset
[0] = 0;
5368 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5370 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5371 This
->stateBlock
->baseVertexIndex
= 0;
5372 This
->stateBlock
->loadBaseVertexIndex
= 0;
5373 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5374 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5375 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5377 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5379 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5380 This
->stateBlock
->streamSource
[0] = NULL
;
5381 This
->stateBlock
->streamStride
[0] = 0;
5382 ib
= This
->stateBlock
->pIndexData
;
5384 IWineD3DIndexBuffer_Release(ib
);
5385 This
->stateBlock
->pIndexData
= NULL
;
5387 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5388 * SetStreamSource to specify a vertex buffer
5394 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5395 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5397 /* Mark the state dirty until we have nicer tracking
5398 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5401 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5402 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5403 This
->stateBlock
->baseVertexIndex
= 0;
5404 This
->up_strided
= DrawPrimStrideData
;
5405 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5406 This
->up_strided
= NULL
;
5410 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5411 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5412 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5414 /* Mark the state dirty until we have nicer tracking
5415 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5418 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5419 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5420 This
->stateBlock
->streamIsUP
= TRUE
;
5421 This
->stateBlock
->baseVertexIndex
= 0;
5422 This
->up_strided
= DrawPrimStrideData
;
5423 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5424 This
->up_strided
= NULL
;
5428 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5429 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5430 * not callable by the app directly no parameter validation checks are needed here.
5432 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5433 WINED3DLOCKED_BOX src
;
5434 WINED3DLOCKED_BOX dst
;
5436 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5438 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5439 * dirtification to improve loading performance.
5441 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5442 if(FAILED(hr
)) return hr
;
5443 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5445 IWineD3DVolume_UnlockBox(pSourceVolume
);
5449 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5451 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5453 IWineD3DVolume_UnlockBox(pSourceVolume
);
5455 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5460 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5461 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5462 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5463 HRESULT hr
= WINED3D_OK
;
5464 WINED3DRESOURCETYPE sourceType
;
5465 WINED3DRESOURCETYPE destinationType
;
5468 /* TODO: think about moving the code into IWineD3DBaseTexture */
5470 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5472 /* verify that the source and destination textures aren't NULL */
5473 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5474 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5475 This
, pSourceTexture
, pDestinationTexture
);
5476 hr
= WINED3DERR_INVALIDCALL
;
5479 if (pSourceTexture
== pDestinationTexture
) {
5480 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5481 This
, pSourceTexture
, pDestinationTexture
);
5482 hr
= WINED3DERR_INVALIDCALL
;
5484 /* Verify that the source and destination textures are the same type */
5485 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5486 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5488 if (sourceType
!= destinationType
) {
5489 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5491 hr
= WINED3DERR_INVALIDCALL
;
5494 /* check that both textures have the identical numbers of levels */
5495 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5496 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5497 hr
= WINED3DERR_INVALIDCALL
;
5500 if (WINED3D_OK
== hr
) {
5502 /* Make sure that the destination texture is loaded */
5503 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5505 /* Update every surface level of the texture */
5506 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5508 switch (sourceType
) {
5509 case WINED3DRTYPE_TEXTURE
:
5511 IWineD3DSurface
*srcSurface
;
5512 IWineD3DSurface
*destSurface
;
5514 for (i
= 0 ; i
< levels
; ++i
) {
5515 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5516 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5517 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5518 IWineD3DSurface_Release(srcSurface
);
5519 IWineD3DSurface_Release(destSurface
);
5520 if (WINED3D_OK
!= hr
) {
5521 WARN("(%p) : Call to update surface failed\n", This
);
5527 case WINED3DRTYPE_CUBETEXTURE
:
5529 IWineD3DSurface
*srcSurface
;
5530 IWineD3DSurface
*destSurface
;
5531 WINED3DCUBEMAP_FACES faceType
;
5533 for (i
= 0 ; i
< levels
; ++i
) {
5534 /* Update each cube face */
5535 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5536 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5537 if (WINED3D_OK
!= hr
) {
5538 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5540 TRACE("Got srcSurface %p\n", srcSurface
);
5542 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5543 if (WINED3D_OK
!= hr
) {
5544 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5546 TRACE("Got desrSurface %p\n", destSurface
);
5548 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5549 IWineD3DSurface_Release(srcSurface
);
5550 IWineD3DSurface_Release(destSurface
);
5551 if (WINED3D_OK
!= hr
) {
5552 WARN("(%p) : Call to update surface failed\n", This
);
5560 case WINED3DRTYPE_VOLUMETEXTURE
:
5562 IWineD3DVolume
*srcVolume
= NULL
;
5563 IWineD3DVolume
*destVolume
= NULL
;
5565 for (i
= 0 ; i
< levels
; ++i
) {
5566 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5567 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5568 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5569 IWineD3DVolume_Release(srcVolume
);
5570 IWineD3DVolume_Release(destVolume
);
5571 if (WINED3D_OK
!= hr
) {
5572 WARN("(%p) : Call to update volume failed\n", This
);
5580 FIXME("(%p) : Unsupported source and destination type\n", This
);
5581 hr
= WINED3DERR_INVALIDCALL
;
5588 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5589 IWineD3DSwapChain
*swapChain
;
5591 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5592 if(hr
== WINED3D_OK
) {
5593 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5594 IWineD3DSwapChain_Release(swapChain
);
5599 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5600 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5601 IWineD3DBaseTextureImpl
*texture
;
5602 const GlPixelFormatDesc
*gl_info
;
5605 TRACE("(%p) : %p\n", This
, pNumPasses
);
5607 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5608 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
5609 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5610 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5612 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
5613 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5614 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5617 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
5618 if(!texture
) continue;
5619 getFormatDescEntry(texture
->resource
.format
, &GLINFO_LOCATION
, &gl_info
);
5620 if(gl_info
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
5622 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
5623 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
5626 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
5627 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
5630 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
5631 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
5632 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
5637 /* return a sensible default */
5640 TRACE("returning D3D_OK\n");
5644 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5648 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5649 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5650 if (texture
&& (texture
->resource
.format
== WINED3DFMT_P8
|| texture
->resource
.format
== WINED3DFMT_A8P8
)) {
5651 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5656 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5657 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5660 PALETTEENTRY
**palettes
;
5662 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5664 if (PaletteNumber
>= MAX_PALETTES
) {
5665 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5666 return WINED3DERR_INVALIDCALL
;
5669 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5670 NewSize
= This
->NumberOfPalettes
;
5673 } while(PaletteNumber
>= NewSize
);
5674 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5676 ERR("Out of memory!\n");
5677 return E_OUTOFMEMORY
;
5679 This
->palettes
= palettes
;
5680 This
->NumberOfPalettes
= NewSize
;
5683 if (!This
->palettes
[PaletteNumber
]) {
5684 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5685 if (!This
->palettes
[PaletteNumber
]) {
5686 ERR("Out of memory!\n");
5687 return E_OUTOFMEMORY
;
5691 for (j
= 0; j
< 256; ++j
) {
5692 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5693 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5694 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5695 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5697 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5698 TRACE("(%p) : returning\n", This
);
5702 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5703 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5705 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5706 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5707 /* What happens in such situation isn't documented; Native seems to silently abort
5708 on such conditions. Return Invalid Call. */
5709 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5710 return WINED3DERR_INVALIDCALL
;
5712 for (j
= 0; j
< 256; ++j
) {
5713 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5714 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5715 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5716 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5718 TRACE("(%p) : returning\n", This
);
5722 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5723 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5724 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5725 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5726 (tested with reference rasterizer). Return Invalid Call. */
5727 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5728 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5729 return WINED3DERR_INVALIDCALL
;
5731 /*TODO: stateblocks */
5732 if (This
->currentPalette
!= PaletteNumber
) {
5733 This
->currentPalette
= PaletteNumber
;
5734 dirtify_p8_texture_samplers(This
);
5736 TRACE("(%p) : returning\n", This
);
5740 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5741 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5742 if (PaletteNumber
== NULL
) {
5743 WARN("(%p) : returning Invalid Call\n", This
);
5744 return WINED3DERR_INVALIDCALL
;
5746 /*TODO: stateblocks */
5747 *PaletteNumber
= This
->currentPalette
;
5748 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5752 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5753 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5754 static BOOL showFixmes
= TRUE
;
5756 FIXME("(%p) : stub\n", This
);
5760 This
->softwareVertexProcessing
= bSoftware
;
5765 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5766 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5767 static BOOL showFixmes
= TRUE
;
5769 FIXME("(%p) : stub\n", This
);
5772 return This
->softwareVertexProcessing
;
5776 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5777 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5778 IWineD3DSwapChain
*swapChain
;
5781 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5783 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5784 if(hr
== WINED3D_OK
){
5785 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5786 IWineD3DSwapChain_Release(swapChain
);
5788 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5794 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5795 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5796 static BOOL showfixmes
= TRUE
;
5797 if(nSegments
!= 0.0f
) {
5799 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5806 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5808 static BOOL showfixmes
= TRUE
;
5810 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5816 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5817 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5818 /** TODO: remove casts to IWineD3DSurfaceImpl
5819 * NOTE: move code to surface to accomplish this
5820 ****************************************/
5821 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5822 int srcWidth
, srcHeight
;
5823 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5824 WINED3DFORMAT destFormat
, srcFormat
;
5826 int srcLeft
, destLeft
, destTop
;
5827 WINED3DPOOL srcPool
, destPool
;
5829 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5830 glDescriptor
*glDescription
= NULL
;
5834 CONVERT_TYPES convert
= NO_CONVERSION
;
5836 WINED3DSURFACE_DESC winedesc
;
5838 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5839 memset(&winedesc
, 0, sizeof(winedesc
));
5840 winedesc
.Width
= &srcSurfaceWidth
;
5841 winedesc
.Height
= &srcSurfaceHeight
;
5842 winedesc
.Pool
= &srcPool
;
5843 winedesc
.Format
= &srcFormat
;
5845 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5847 winedesc
.Width
= &destSurfaceWidth
;
5848 winedesc
.Height
= &destSurfaceHeight
;
5849 winedesc
.Pool
= &destPool
;
5850 winedesc
.Format
= &destFormat
;
5851 winedesc
.Size
= &destSize
;
5853 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5855 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5856 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5857 return WINED3DERR_INVALIDCALL
;
5860 /* This call loads the opengl surface directly, instead of copying the surface to the
5861 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5862 * copy in sysmem and use regular surface loading.
5864 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5865 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5866 if(convert
!= NO_CONVERSION
) {
5867 return IWineD3DSurface_BltFast(pDestinationSurface
,
5868 pDestPoint
? pDestPoint
->x
: 0,
5869 pDestPoint
? pDestPoint
->y
: 0,
5870 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5873 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5874 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5875 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5877 /* Get the update surface description */
5878 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5881 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5883 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5885 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5886 checkGLcall("glActiveTextureARB");
5890 /* Make sure the surface is loaded and up to date */
5891 IWineD3DSurface_PreLoad(pDestinationSurface
);
5892 IWineD3DSurface_BindTexture(pDestinationSurface
);
5894 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5896 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5897 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5898 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5899 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5900 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5901 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5904 /* This function doesn't support compressed textures
5905 the pitch is just bytesPerPixel * width */
5906 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5907 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5908 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5909 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5911 /* TODO DXT formats */
5913 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5914 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5916 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5917 This
, glDescription
->level
, destLeft
, destTop
, srcWidth
, srcHeight
, glDescription
->glFormat
,
5918 glDescription
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5921 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5923 /* need to lock the surface to get the data */
5924 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5929 /* TODO: Cube and volume support */
5931 /* not a whole row so we have to do it a line at a time */
5934 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5935 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5937 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5939 glTexSubImage2D(glDescription
->target
5940 ,glDescription
->level
5945 ,glDescription
->glFormat
5946 ,glDescription
->glType
5947 ,data
/* could be quicker using */
5952 } else { /* Full width, so just write out the whole texture */
5953 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5955 if (WINED3DFMT_DXT1
== destFormat
||
5956 WINED3DFMT_DXT2
== destFormat
||
5957 WINED3DFMT_DXT3
== destFormat
||
5958 WINED3DFMT_DXT4
== destFormat
||
5959 WINED3DFMT_DXT5
== destFormat
) {
5960 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5961 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5962 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5963 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5964 } if (destFormat
!= srcFormat
) {
5965 FIXME("Updating mixed format compressed texture is not curretly support\n");
5967 GL_EXTCALL(glCompressedTexImage2DARB(glDescription
->target
, glDescription
->level
,
5968 glDescription
->glFormatInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5971 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5976 glTexSubImage2D(glDescription
->target
, glDescription
->level
, destLeft
, destTop
,
5977 srcWidth
, srcHeight
, glDescription
->glFormat
, glDescription
->glType
, data
);
5980 checkGLcall("glTexSubImage2D");
5984 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5985 sampler
= This
->rev_tex_unit_map
[0];
5986 if (sampler
!= -1) {
5987 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5993 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5994 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5995 struct WineD3DRectPatch
*patch
;
5999 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
6001 if(!(Handle
|| pRectPatchInfo
)) {
6002 /* TODO: Write a test for the return value, thus the FIXME */
6003 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6004 return WINED3DERR_INVALIDCALL
;
6008 i
= PATCHMAP_HASHFUNC(Handle
);
6010 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6011 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6012 if(patch
->Handle
== Handle
) {
6019 TRACE("Patch does not exist. Creating a new one\n");
6020 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6021 patch
->Handle
= Handle
;
6022 list_add_head(&This
->patches
[i
], &patch
->entry
);
6024 TRACE("Found existing patch %p\n", patch
);
6027 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6028 * attributes we have to tesselate, read back, and draw. This needs a patch
6029 * management structure instance. Create one.
6031 * A possible improvement is to check if a vertex shader is used, and if not directly
6034 FIXME("Drawing an uncached patch. This is slow\n");
6035 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6038 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
6039 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
6040 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
6042 TRACE("Tesselation density or patch info changed, retesselating\n");
6044 if(pRectPatchInfo
) {
6045 patch
->RectPatchInfo
= *pRectPatchInfo
;
6047 patch
->numSegs
[0] = pNumSegs
[0];
6048 patch
->numSegs
[1] = pNumSegs
[1];
6049 patch
->numSegs
[2] = pNumSegs
[2];
6050 patch
->numSegs
[3] = pNumSegs
[3];
6052 hr
= tesselate_rectpatch(This
, patch
);
6054 WARN("Patch tesselation failed\n");
6056 /* Do not release the handle to store the params of the patch */
6058 HeapFree(GetProcessHeap(), 0, patch
);
6064 This
->currentPatch
= patch
;
6065 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
6066 This
->currentPatch
= NULL
;
6068 /* Destroy uncached patches */
6070 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6071 HeapFree(GetProcessHeap(), 0, patch
);
6076 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
6077 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6078 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
6079 FIXME("(%p) : Stub\n", This
);
6083 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
6084 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6086 struct WineD3DRectPatch
*patch
;
6088 TRACE("(%p) Handle(%d)\n", This
, Handle
);
6090 i
= PATCHMAP_HASHFUNC(Handle
);
6091 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6092 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6093 if(patch
->Handle
== Handle
) {
6094 TRACE("Deleting patch %p\n", patch
);
6095 list_remove(&patch
->entry
);
6096 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6097 HeapFree(GetProcessHeap(), 0, patch
);
6102 /* TODO: Write a test for the return value */
6103 FIXME("Attempt to destroy nonexistent patch\n");
6104 return WINED3DERR_INVALIDCALL
;
6107 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6109 IWineD3DSwapChain
*swapchain
;
6111 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6112 if (SUCCEEDED(hr
)) {
6113 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6120 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
6121 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6122 IWineD3DSwapChain
*swapchain
;
6124 swapchain
= get_swapchain(surface
);
6128 TRACE("Surface %p is onscreen\n", surface
);
6130 ActivateContext(This
, surface
, CTXUSAGE_RESOURCELOAD
);
6132 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6133 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6134 glDrawBuffer(buffer
);
6135 checkGLcall("glDrawBuffer()");
6137 TRACE("Surface %p is offscreen\n", surface
);
6139 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6141 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6142 context_attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6143 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6144 checkGLcall("glFramebufferRenderbufferEXT");
6148 glEnable(GL_SCISSOR_TEST
);
6150 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6152 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6153 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6155 checkGLcall("glScissor");
6156 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
6158 glDisable(GL_SCISSOR_TEST
);
6160 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6162 glDisable(GL_BLEND
);
6163 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
6165 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6166 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6168 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
6169 glClear(GL_COLOR_BUFFER_BIT
);
6170 checkGLcall("glClear");
6172 if (This
->activeContext
->current_fbo
) {
6173 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6175 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6176 checkGLcall("glBindFramebuffer()");
6179 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6180 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6181 glDrawBuffer(GL_BACK
);
6182 checkGLcall("glDrawBuffer()");
6188 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6189 unsigned int r
, g
, b
, a
;
6192 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6193 destfmt
== WINED3DFMT_R8G8B8
)
6196 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6198 a
= (color
& 0xff000000) >> 24;
6199 r
= (color
& 0x00ff0000) >> 16;
6200 g
= (color
& 0x0000ff00) >> 8;
6201 b
= (color
& 0x000000ff) >> 0;
6205 case WINED3DFMT_R5G6B5
:
6206 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6213 TRACE("Returning %08x\n", ret
);
6216 case WINED3DFMT_X1R5G5B5
:
6217 case WINED3DFMT_A1R5G5B5
:
6226 TRACE("Returning %08x\n", ret
);
6230 TRACE("Returning %08x\n", a
);
6233 case WINED3DFMT_X4R4G4B4
:
6234 case WINED3DFMT_A4R4G4B4
:
6243 TRACE("Returning %08x\n", ret
);
6246 case WINED3DFMT_R3G3B2
:
6253 TRACE("Returning %08x\n", ret
);
6256 case WINED3DFMT_X8B8G8R8
:
6257 case WINED3DFMT_A8B8G8R8
:
6262 TRACE("Returning %08x\n", ret
);
6265 case WINED3DFMT_A2R10G10B10
:
6267 r
= (r
* 1024) / 256;
6268 g
= (g
* 1024) / 256;
6269 b
= (b
* 1024) / 256;
6274 TRACE("Returning %08x\n", ret
);
6277 case WINED3DFMT_A2B10G10R10
:
6279 r
= (r
* 1024) / 256;
6280 g
= (g
* 1024) / 256;
6281 b
= (b
* 1024) / 256;
6286 TRACE("Returning %08x\n", ret
);
6290 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6295 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6296 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6297 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6299 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6301 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6302 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6303 return WINED3DERR_INVALIDCALL
;
6306 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6307 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6310 /* Just forward this to the DirectDraw blitting engine */
6311 memset(&BltFx
, 0, sizeof(BltFx
));
6312 BltFx
.dwSize
= sizeof(BltFx
);
6313 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6314 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6318 /* rendertarget and depth stencil functions */
6319 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6320 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6322 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6323 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6324 return WINED3DERR_INVALIDCALL
;
6327 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6328 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6329 /* Note inc ref on returned surface */
6330 if(*ppRenderTarget
!= NULL
)
6331 IWineD3DSurface_AddRef(*ppRenderTarget
);
6335 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6336 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6337 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6338 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6339 IWineD3DSwapChainImpl
*Swapchain
;
6342 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6344 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6345 if(hr
!= WINED3D_OK
) {
6346 ERR("Can't get the swapchain\n");
6350 /* Make sure to release the swapchain */
6351 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6353 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6354 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6355 return WINED3DERR_INVALIDCALL
;
6357 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6358 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6359 return WINED3DERR_INVALIDCALL
;
6362 if(Swapchain
->frontBuffer
!= Front
) {
6363 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6365 if(Swapchain
->frontBuffer
)
6366 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6367 Swapchain
->frontBuffer
= Front
;
6369 if(Swapchain
->frontBuffer
) {
6370 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6374 if(Back
&& !Swapchain
->backBuffer
) {
6375 /* We need memory for the back buffer array - only one back buffer this way */
6376 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6377 if(!Swapchain
->backBuffer
) {
6378 ERR("Out of memory\n");
6379 return E_OUTOFMEMORY
;
6383 if(Swapchain
->backBuffer
[0] != Back
) {
6384 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6386 /* What to do about the context here in the case of multithreading? Not sure.
6387 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6390 if(!Swapchain
->backBuffer
[0]) {
6391 /* GL was told to draw to the front buffer at creation,
6394 glDrawBuffer(GL_BACK
);
6395 checkGLcall("glDrawBuffer(GL_BACK)");
6396 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6397 Swapchain
->presentParms
.BackBufferCount
= 1;
6399 /* That makes problems - disable for now */
6400 /* glDrawBuffer(GL_FRONT); */
6401 checkGLcall("glDrawBuffer(GL_FRONT)");
6402 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6403 Swapchain
->presentParms
.BackBufferCount
= 0;
6407 if(Swapchain
->backBuffer
[0])
6408 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6409 Swapchain
->backBuffer
[0] = Back
;
6411 if(Swapchain
->backBuffer
[0]) {
6412 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6414 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6415 Swapchain
->backBuffer
= NULL
;
6423 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6424 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6425 *ppZStencilSurface
= This
->stencilBufferTarget
;
6426 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6428 if(*ppZStencilSurface
!= NULL
) {
6429 /* Note inc ref on returned surface */
6430 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6433 return WINED3DERR_NOTFOUND
;
6437 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6438 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6439 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6440 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6441 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6443 POINT offset
= {0, 0};
6445 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6446 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6447 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6448 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6451 case WINED3DTEXF_LINEAR
:
6452 gl_filter
= GL_LINEAR
;
6456 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6457 case WINED3DTEXF_NONE
:
6458 case WINED3DTEXF_POINT
:
6459 gl_filter
= GL_NEAREST
;
6463 /* Attach src surface to src fbo */
6464 src_swapchain
= get_swapchain(src_surface
);
6465 if (src_swapchain
) {
6466 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6468 TRACE("Source surface %p is onscreen\n", src_surface
);
6469 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6470 /* Make sure the drawable is up to date. In the offscreen case
6471 * attach_surface_fbo() implicitly takes care of this. */
6472 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6474 if(buffer
== GL_FRONT
) {
6477 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
6478 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
6479 h
= windowsize
.bottom
- windowsize
.top
;
6480 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6481 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6482 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6484 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6485 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6489 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6490 glReadBuffer(buffer
);
6491 checkGLcall("glReadBuffer()");
6493 TRACE("Source surface %p is offscreen\n", src_surface
);
6495 context_bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->activeContext
->src_fbo
);
6496 context_attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6497 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6498 checkGLcall("glReadBuffer()");
6499 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6500 checkGLcall("glFramebufferRenderbufferEXT");
6504 /* Attach dst surface to dst fbo */
6505 dst_swapchain
= get_swapchain(dst_surface
);
6506 if (dst_swapchain
) {
6507 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6509 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6510 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6511 /* Make sure the drawable is up to date. In the offscreen case
6512 * attach_surface_fbo() implicitly takes care of this. */
6513 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6515 if(buffer
== GL_FRONT
) {
6518 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
6519 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
6520 h
= windowsize
.bottom
- windowsize
.top
;
6521 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6522 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6523 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6525 /* Screen coords = window coords, surface height = window height */
6526 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6527 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6531 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6532 glDrawBuffer(buffer
);
6533 checkGLcall("glDrawBuffer()");
6535 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6537 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6538 if(!src_swapchain
) {
6539 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6543 context_bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6544 context_attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6545 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6546 checkGLcall("glDrawBuffer()");
6547 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6548 checkGLcall("glFramebufferRenderbufferEXT");
6550 glDisable(GL_SCISSOR_TEST
);
6551 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6554 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6555 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6556 checkGLcall("glBlitFramebuffer()");
6558 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6559 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6560 checkGLcall("glBlitFramebuffer()");
6563 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6565 if (This
->activeContext
->current_fbo
) {
6566 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6568 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6569 checkGLcall("glBindFramebuffer()");
6572 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6573 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6574 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6575 glDrawBuffer(GL_BACK
);
6576 checkGLcall("glDrawBuffer()");
6581 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6583 WINED3DVIEWPORT viewport
;
6585 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6587 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6588 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6589 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6590 return WINED3DERR_INVALIDCALL
;
6593 /* MSDN says that null disables the render target
6594 but a device must always be associated with a render target
6595 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6597 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6598 FIXME("Trying to set render target 0 to NULL\n");
6599 return WINED3DERR_INVALIDCALL
;
6601 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6602 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
);
6603 return WINED3DERR_INVALIDCALL
;
6606 /* If we are trying to set what we already have, don't bother */
6607 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6608 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6611 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6612 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6613 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6615 /* Render target 0 is special */
6616 if(RenderTargetIndex
== 0) {
6617 /* Finally, reset the viewport as the MSDN states. */
6618 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6619 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6622 viewport
.MaxZ
= 1.0f
;
6623 viewport
.MinZ
= 0.0f
;
6624 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6625 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6626 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6628 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6633 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6634 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6635 HRESULT hr
= WINED3D_OK
;
6636 IWineD3DSurface
*tmp
;
6638 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6640 if (pNewZStencil
== This
->stencilBufferTarget
) {
6641 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6643 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6644 * depending on the renter target implementation being used.
6645 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6646 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6647 * stencil buffer and incur an extra memory overhead
6648 ******************************************************/
6650 if (This
->stencilBufferTarget
) {
6651 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6652 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
6653 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
6655 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6656 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6657 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6661 tmp
= This
->stencilBufferTarget
;
6662 This
->stencilBufferTarget
= pNewZStencil
;
6663 /* should we be calling the parent or the wined3d surface? */
6664 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6665 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6668 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6669 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6670 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6671 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6672 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6679 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6680 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6681 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6682 /* TODO: the use of Impl is deprecated. */
6683 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6684 WINED3DLOCKED_RECT lockedRect
;
6686 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6688 /* some basic validation checks */
6689 if(This
->cursorTexture
) {
6690 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6692 glDeleteTextures(1, &This
->cursorTexture
);
6694 This
->cursorTexture
= 0;
6697 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6698 This
->haveHardwareCursor
= TRUE
;
6700 This
->haveHardwareCursor
= FALSE
;
6703 WINED3DLOCKED_RECT rect
;
6705 /* MSDN: Cursor must be A8R8G8B8 */
6706 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6707 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6708 return WINED3DERR_INVALIDCALL
;
6711 /* MSDN: Cursor must be smaller than the display mode */
6712 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6713 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6714 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
);
6715 return WINED3DERR_INVALIDCALL
;
6718 if (!This
->haveHardwareCursor
) {
6719 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6721 /* Do not store the surface's pointer because the application may
6722 * release it after setting the cursor image. Windows doesn't
6723 * addref the set surface, so we can't do this either without
6724 * creating circular refcount dependencies. Copy out the gl texture
6727 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6728 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6729 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6731 const GlPixelFormatDesc
*glDesc
;
6732 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6733 char *mem
, *bits
= (char *)rect
.pBits
;
6734 GLint intfmt
= glDesc
->glInternal
;
6735 GLint format
= glDesc
->glFormat
;
6736 GLint type
= glDesc
->glType
;
6737 INT height
= This
->cursorHeight
;
6738 INT width
= This
->cursorWidth
;
6739 INT bpp
= tableEntry
->bpp
;
6742 /* Reformat the texture memory (pitch and width can be
6744 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6745 for(i
= 0; i
< height
; i
++)
6746 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6747 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6750 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6751 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6752 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6755 /* Make sure that a proper texture unit is selected */
6756 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6757 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6758 checkGLcall("glActiveTextureARB");
6760 sampler
= This
->rev_tex_unit_map
[0];
6761 if (sampler
!= -1) {
6762 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6764 /* Create a new cursor texture */
6765 glGenTextures(1, &This
->cursorTexture
);
6766 checkGLcall("glGenTextures");
6767 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6768 checkGLcall("glBindTexture");
6769 /* Copy the bitmap memory into the cursor texture */
6770 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6771 HeapFree(GetProcessHeap(), 0, mem
);
6772 checkGLcall("glTexImage2D");
6774 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6775 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6776 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6783 FIXME("A cursor texture was not returned.\n");
6784 This
->cursorTexture
= 0;
6789 /* Draw a hardware cursor */
6790 ICONINFO cursorInfo
;
6792 /* Create and clear maskBits because it is not needed for
6793 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6795 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6796 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6797 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6798 WINED3DLOCK_NO_DIRTY_UPDATE
|
6799 WINED3DLOCK_READONLY
6801 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6802 pSur
->currentDesc
.Height
);
6804 cursorInfo
.fIcon
= FALSE
;
6805 cursorInfo
.xHotspot
= XHotSpot
;
6806 cursorInfo
.yHotspot
= YHotSpot
;
6807 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6808 pSur
->currentDesc
.Height
, 1,
6810 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6811 pSur
->currentDesc
.Height
, 1,
6812 32, lockedRect
.pBits
);
6813 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6814 /* Create our cursor and clean up. */
6815 cursor
= CreateIconIndirect(&cursorInfo
);
6817 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6818 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6819 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6820 This
->hardwareCursor
= cursor
;
6821 HeapFree(GetProcessHeap(), 0, maskBits
);
6825 This
->xHotSpot
= XHotSpot
;
6826 This
->yHotSpot
= YHotSpot
;
6830 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6831 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6832 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6834 This
->xScreenSpace
= XScreenSpace
;
6835 This
->yScreenSpace
= YScreenSpace
;
6841 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6842 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6843 BOOL oldVisible
= This
->bCursorVisible
;
6846 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6849 * When ShowCursor is first called it should make the cursor appear at the OS's last
6850 * known cursor position. Because of this, some applications just repetitively call
6851 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6854 This
->xScreenSpace
= pt
.x
;
6855 This
->yScreenSpace
= pt
.y
;
6857 if (This
->haveHardwareCursor
) {
6858 This
->bCursorVisible
= bShow
;
6860 SetCursor(This
->hardwareCursor
);
6866 if (This
->cursorTexture
)
6867 This
->bCursorVisible
= bShow
;
6873 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6874 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6875 IWineD3DResourceImpl
*resource
;
6876 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6878 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6879 switch (This
->state
) {
6882 case WINED3DERR_DEVICELOST
:
6884 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6885 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
6886 return WINED3DERR_DEVICENOTRESET
;
6888 return WINED3DERR_DEVICELOST
;
6890 case WINED3DERR_DRIVERINTERNALERROR
:
6891 return WINED3DERR_DRIVERINTERNALERROR
;
6895 return WINED3DERR_DRIVERINTERNALERROR
;
6899 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6900 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6901 /** FIXME: Resource tracking needs to be done,
6902 * The closes we can do to this is set the priorities of all managed textures low
6903 * and then reset them.
6904 ***********************************************************/
6905 FIXME("(%p) : stub\n", This
);
6909 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6910 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6912 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6913 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6914 /* Release the DC */
6915 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6916 DeleteDC(surface
->hDC
);
6917 /* Release the DIB section */
6918 DeleteObject(surface
->dib
.DIBsection
);
6919 surface
->dib
.bitmap_data
= NULL
;
6920 surface
->resource
.allocatedMemory
= NULL
;
6921 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6923 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6924 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6925 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
6926 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
6927 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6928 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6930 surface
->pow2Width
= surface
->pow2Height
= 1;
6931 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6932 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6934 surface
->glRect
.left
= 0;
6935 surface
->glRect
.top
= 0;
6936 surface
->glRect
.right
= surface
->pow2Width
;
6937 surface
->glRect
.bottom
= surface
->pow2Height
;
6939 if(surface
->glDescription
.textureName
) {
6940 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6942 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6944 surface
->glDescription
.textureName
= 0;
6945 surface
->Flags
&= ~SFLAG_CLIENT
;
6947 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6948 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6949 surface
->Flags
|= SFLAG_NONPOW2
;
6951 surface
->Flags
&= ~SFLAG_NONPOW2
;
6953 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6954 surface
->resource
.allocatedMemory
= NULL
;
6955 surface
->resource
.heapMemory
= NULL
;
6956 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6957 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6958 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
6959 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
6961 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
6965 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6966 TRACE("Unloading resource %p\n", resource
);
6967 IWineD3DResource_UnLoad(resource
);
6968 IWineD3DResource_Release(resource
);
6972 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, WINED3DPRESENT_PARAMETERS
*pp
) {
6974 WINED3DDISPLAYMODE m
;
6977 /* All Windowed modes are supported, as is leaving the current mode */
6978 if(pp
->Windowed
) return TRUE
;
6979 if(!pp
->BackBufferWidth
) return TRUE
;
6980 if(!pp
->BackBufferHeight
) return TRUE
;
6982 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
6983 for(i
= 0; i
< count
; i
++) {
6984 memset(&m
, 0, sizeof(m
));
6985 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
6987 ERR("EnumAdapterModes failed\n");
6989 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6990 /* Mode found, it is supported */
6994 /* Mode not found -> not supported */
6998 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6999 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7000 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
7002 IWineD3DBaseShaderImpl
*shader
;
7004 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
7005 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
7006 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
7010 if(This
->depth_blt_texture
) {
7011 glDeleteTextures(1, &This
->depth_blt_texture
);
7012 This
->depth_blt_texture
= 0;
7014 if (This
->depth_blt_rb
) {
7015 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
7016 This
->depth_blt_rb
= 0;
7017 This
->depth_blt_rb_w
= 0;
7018 This
->depth_blt_rb_h
= 0;
7022 This
->blitter
->free_private(iface
);
7023 This
->frag_pipe
->free_private(iface
);
7024 This
->shader_backend
->shader_free_private(iface
);
7027 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
7028 /* Textures are recreated below */
7029 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
7030 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7031 This
->dummyTextureName
[i
] = 0;
7035 while(This
->numContexts
) {
7036 DestroyContext(This
, This
->contexts
[0]);
7038 This
->activeContext
= NULL
;
7039 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
7040 swapchain
->context
= NULL
;
7041 swapchain
->num_contexts
= 0;
7044 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
7045 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7046 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
7048 IWineD3DSurfaceImpl
*target
;
7050 /* Recreate the primary swapchain's context */
7051 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
7052 if(swapchain
->backBuffer
) {
7053 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
7055 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
7057 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
7058 &swapchain
->presentParms
);
7059 swapchain
->num_contexts
= 1;
7060 This
->activeContext
= swapchain
->context
[0];
7062 create_dummy_textures(This
);
7064 hr
= This
->shader_backend
->shader_alloc_private(iface
);
7066 ERR("Failed to recreate shader private data\n");
7069 hr
= This
->frag_pipe
->alloc_private(iface
);
7071 TRACE("Fragment pipeline private data couldn't be allocated\n");
7074 hr
= This
->blitter
->alloc_private(iface
);
7076 TRACE("Blitter private data couldn't be allocated\n");
7083 This
->blitter
->free_private(iface
);
7084 This
->frag_pipe
->free_private(iface
);
7085 This
->shader_backend
->shader_free_private(iface
);
7089 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7090 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7091 IWineD3DSwapChainImpl
*swapchain
;
7093 BOOL DisplayModeChanged
= FALSE
;
7094 WINED3DDISPLAYMODE mode
;
7095 TRACE("(%p)\n", This
);
7097 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7099 ERR("Failed to get the first implicit swapchain\n");
7103 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7104 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7105 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7106 pPresentationParameters
->BackBufferHeight
);
7107 return WINED3DERR_INVALIDCALL
;
7110 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7111 * on an existing gl context, so there's no real need for recreation.
7113 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7115 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7117 TRACE("New params:\n");
7118 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7119 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7120 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7121 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7122 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7123 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7124 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7125 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7126 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7127 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7128 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7129 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7130 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7132 /* No special treatment of these parameters. Just store them */
7133 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7134 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7135 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7136 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7138 /* What to do about these? */
7139 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7140 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7141 ERR("Cannot change the back buffer count yet\n");
7143 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7144 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7145 ERR("Cannot change the back buffer format yet\n");
7147 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7148 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7149 ERR("Cannot change the device window yet\n");
7151 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
7152 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7153 return WINED3DERR_INVALIDCALL
;
7156 /* Reset the depth stencil */
7157 if (pPresentationParameters
->EnableAutoDepthStencil
)
7158 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
7160 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
7162 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
7164 if(pPresentationParameters
->Windowed
) {
7165 mode
.Width
= swapchain
->orig_width
;
7166 mode
.Height
= swapchain
->orig_height
;
7167 mode
.RefreshRate
= 0;
7168 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7170 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7171 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7172 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7173 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7176 /* Should Width == 800 && Height == 0 set 800x600? */
7177 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7178 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7179 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7186 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
7187 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
7191 if(!pPresentationParameters
->Windowed
) {
7192 DisplayModeChanged
= TRUE
;
7194 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7195 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7197 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7198 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7199 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7201 if(This
->auto_depth_stencil_buffer
) {
7202 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7206 /* Now set the new viewport */
7207 IWineD3DDevice_SetViewport(iface
, &vp
);
7210 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7211 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7212 DisplayModeChanged
) {
7214 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7216 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
7217 if(swapchain
->presentParms
.Windowed
) {
7218 /* switch from windowed to fs */
7219 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7220 pPresentationParameters
->BackBufferWidth
,
7221 pPresentationParameters
->BackBufferHeight
);
7223 /* Fullscreen -> fullscreen mode change */
7224 MoveWindow(swapchain
->win_handle
, 0, 0,
7225 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
7228 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
7229 /* Fullscreen -> windowed switch */
7230 IWineD3DDeviceImpl_RestoreWindow(iface
, swapchain
->win_handle
);
7232 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7233 } else if(!pPresentationParameters
->Windowed
) {
7234 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7235 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7236 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7237 * Reset to clear up their mess. Guild Wars also loses the device during that.
7241 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7242 pPresentationParameters
->BackBufferWidth
,
7243 pPresentationParameters
->BackBufferHeight
);
7244 This
->style
= style
;
7245 This
->exStyle
= exStyle
;
7248 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7250 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7253 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
7254 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7256 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7262 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7263 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7264 /** FIXME: always true at the moment **/
7265 if(!bEnableDialogs
) {
7266 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7272 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7273 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7274 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7276 *pParameters
= This
->createParms
;
7280 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7281 IWineD3DSwapChain
*swapchain
;
7283 TRACE("Relaying to swapchain\n");
7285 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7286 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
7287 IWineD3DSwapChain_Release(swapchain
);
7292 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7293 IWineD3DSwapChain
*swapchain
;
7295 TRACE("Relaying to swapchain\n");
7297 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7298 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7299 IWineD3DSwapChain_Release(swapchain
);
7305 /** ********************************************************
7306 * Notification functions
7307 ** ********************************************************/
7308 /** This function must be called in the release of a resource when ref == 0,
7309 * the contents of resource must still be correct,
7310 * any handles to other resource held by the caller must be closed
7311 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7312 *****************************************************/
7313 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7316 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7317 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7320 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7321 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7323 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7325 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7329 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7330 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7331 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
7334 TRACE("(%p) : resource %p\n", This
, resource
);
7336 context_resource_released(iface
, resource
, type
);
7339 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7340 case WINED3DRTYPE_SURFACE
: {
7343 /* Cleanup any FBO attachments if d3d is enabled */
7344 if(This
->d3d_initialized
) {
7345 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7346 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7348 TRACE("Last active render target destroyed\n");
7349 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7350 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7351 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7352 * and the lastActiveRenderTarget member shouldn't matter
7355 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7356 TRACE("Activating primary back buffer\n");
7357 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7358 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7359 /* Single buffering environment */
7360 TRACE("Activating primary front buffer\n");
7361 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7363 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7364 /* Implicit render target destroyed, that means the device is being destroyed
7365 * whatever we set here, it shouldn't matter
7367 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7370 /* May happen during ddraw uninitialization */
7371 TRACE("Render target set, but swapchain does not exist!\n");
7372 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7376 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7377 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
7378 This
->render_targets
[i
] = NULL
;
7381 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
7382 This
->stencilBufferTarget
= NULL
;
7388 case WINED3DRTYPE_TEXTURE
:
7389 case WINED3DRTYPE_CUBETEXTURE
:
7390 case WINED3DRTYPE_VOLUMETEXTURE
:
7391 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7392 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7393 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7394 This
->stateBlock
->textures
[counter
] = NULL
;
7396 if (This
->updateStateBlock
!= This
->stateBlock
){
7397 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7398 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7399 This
->updateStateBlock
->textures
[counter
] = NULL
;
7404 case WINED3DRTYPE_VOLUME
:
7405 /* TODO: nothing really? */
7407 case WINED3DRTYPE_VERTEXBUFFER
:
7408 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7411 TRACE("Cleaning up stream pointers\n");
7413 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7414 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7415 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7417 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7418 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7419 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7420 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7421 /* Set changed flag? */
7424 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) */
7425 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7426 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7427 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7433 case WINED3DRTYPE_INDEXBUFFER
:
7434 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7435 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7436 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7437 This
->updateStateBlock
->pIndexData
= NULL
;
7440 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7441 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7442 This
->stateBlock
->pIndexData
= NULL
;
7448 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7453 /* Remove the resource from the resourceStore */
7454 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7456 TRACE("Resource released\n");
7460 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7461 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7462 IWineD3DResourceImpl
*resource
, *cursor
;
7464 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7466 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7467 TRACE("enumerating resource %p\n", resource
);
7468 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7469 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7470 if(ret
== S_FALSE
) {
7471 TRACE("Canceling enumeration\n");
7478 /**********************************************************
7479 * IWineD3DDevice VTbl follows
7480 **********************************************************/
7482 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7484 /*** IUnknown methods ***/
7485 IWineD3DDeviceImpl_QueryInterface
,
7486 IWineD3DDeviceImpl_AddRef
,
7487 IWineD3DDeviceImpl_Release
,
7488 /*** IWineD3DDevice methods ***/
7489 IWineD3DDeviceImpl_GetParent
,
7490 /*** Creation methods**/
7491 IWineD3DDeviceImpl_CreateVertexBuffer
,
7492 IWineD3DDeviceImpl_CreateIndexBuffer
,
7493 IWineD3DDeviceImpl_CreateStateBlock
,
7494 IWineD3DDeviceImpl_CreateSurface
,
7495 IWineD3DDeviceImpl_CreateTexture
,
7496 IWineD3DDeviceImpl_CreateVolumeTexture
,
7497 IWineD3DDeviceImpl_CreateVolume
,
7498 IWineD3DDeviceImpl_CreateCubeTexture
,
7499 IWineD3DDeviceImpl_CreateQuery
,
7500 IWineD3DDeviceImpl_CreateSwapChain
,
7501 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7502 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7503 IWineD3DDeviceImpl_CreateVertexShader
,
7504 IWineD3DDeviceImpl_CreatePixelShader
,
7505 IWineD3DDeviceImpl_CreatePalette
,
7506 /*** Odd functions **/
7507 IWineD3DDeviceImpl_Init3D
,
7508 IWineD3DDeviceImpl_InitGDI
,
7509 IWineD3DDeviceImpl_Uninit3D
,
7510 IWineD3DDeviceImpl_UninitGDI
,
7511 IWineD3DDeviceImpl_SetMultithreaded
,
7512 IWineD3DDeviceImpl_EvictManagedResources
,
7513 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7514 IWineD3DDeviceImpl_GetBackBuffer
,
7515 IWineD3DDeviceImpl_GetCreationParameters
,
7516 IWineD3DDeviceImpl_GetDeviceCaps
,
7517 IWineD3DDeviceImpl_GetDirect3D
,
7518 IWineD3DDeviceImpl_GetDisplayMode
,
7519 IWineD3DDeviceImpl_SetDisplayMode
,
7520 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7521 IWineD3DDeviceImpl_GetRasterStatus
,
7522 IWineD3DDeviceImpl_GetSwapChain
,
7523 IWineD3DDeviceImpl_Reset
,
7524 IWineD3DDeviceImpl_SetDialogBoxMode
,
7525 IWineD3DDeviceImpl_SetCursorProperties
,
7526 IWineD3DDeviceImpl_SetCursorPosition
,
7527 IWineD3DDeviceImpl_ShowCursor
,
7528 IWineD3DDeviceImpl_TestCooperativeLevel
,
7529 /*** Getters and setters **/
7530 IWineD3DDeviceImpl_SetClipPlane
,
7531 IWineD3DDeviceImpl_GetClipPlane
,
7532 IWineD3DDeviceImpl_SetClipStatus
,
7533 IWineD3DDeviceImpl_GetClipStatus
,
7534 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7535 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7536 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7537 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7538 IWineD3DDeviceImpl_SetFVF
,
7539 IWineD3DDeviceImpl_GetFVF
,
7540 IWineD3DDeviceImpl_SetGammaRamp
,
7541 IWineD3DDeviceImpl_GetGammaRamp
,
7542 IWineD3DDeviceImpl_SetIndices
,
7543 IWineD3DDeviceImpl_GetIndices
,
7544 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7545 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7546 IWineD3DDeviceImpl_SetLight
,
7547 IWineD3DDeviceImpl_GetLight
,
7548 IWineD3DDeviceImpl_SetLightEnable
,
7549 IWineD3DDeviceImpl_GetLightEnable
,
7550 IWineD3DDeviceImpl_SetMaterial
,
7551 IWineD3DDeviceImpl_GetMaterial
,
7552 IWineD3DDeviceImpl_SetNPatchMode
,
7553 IWineD3DDeviceImpl_GetNPatchMode
,
7554 IWineD3DDeviceImpl_SetPaletteEntries
,
7555 IWineD3DDeviceImpl_GetPaletteEntries
,
7556 IWineD3DDeviceImpl_SetPixelShader
,
7557 IWineD3DDeviceImpl_GetPixelShader
,
7558 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7559 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7560 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7561 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7562 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7563 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7564 IWineD3DDeviceImpl_SetRenderState
,
7565 IWineD3DDeviceImpl_GetRenderState
,
7566 IWineD3DDeviceImpl_SetRenderTarget
,
7567 IWineD3DDeviceImpl_GetRenderTarget
,
7568 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7569 IWineD3DDeviceImpl_SetSamplerState
,
7570 IWineD3DDeviceImpl_GetSamplerState
,
7571 IWineD3DDeviceImpl_SetScissorRect
,
7572 IWineD3DDeviceImpl_GetScissorRect
,
7573 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7574 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7575 IWineD3DDeviceImpl_SetStreamSource
,
7576 IWineD3DDeviceImpl_GetStreamSource
,
7577 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7578 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7579 IWineD3DDeviceImpl_SetTexture
,
7580 IWineD3DDeviceImpl_GetTexture
,
7581 IWineD3DDeviceImpl_SetTextureStageState
,
7582 IWineD3DDeviceImpl_GetTextureStageState
,
7583 IWineD3DDeviceImpl_SetTransform
,
7584 IWineD3DDeviceImpl_GetTransform
,
7585 IWineD3DDeviceImpl_SetVertexDeclaration
,
7586 IWineD3DDeviceImpl_GetVertexDeclaration
,
7587 IWineD3DDeviceImpl_SetVertexShader
,
7588 IWineD3DDeviceImpl_GetVertexShader
,
7589 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7590 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7591 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7592 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7593 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7594 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7595 IWineD3DDeviceImpl_SetViewport
,
7596 IWineD3DDeviceImpl_GetViewport
,
7597 IWineD3DDeviceImpl_MultiplyTransform
,
7598 IWineD3DDeviceImpl_ValidateDevice
,
7599 IWineD3DDeviceImpl_ProcessVertices
,
7600 /*** State block ***/
7601 IWineD3DDeviceImpl_BeginStateBlock
,
7602 IWineD3DDeviceImpl_EndStateBlock
,
7603 /*** Scene management ***/
7604 IWineD3DDeviceImpl_BeginScene
,
7605 IWineD3DDeviceImpl_EndScene
,
7606 IWineD3DDeviceImpl_Present
,
7607 IWineD3DDeviceImpl_Clear
,
7609 IWineD3DDeviceImpl_DrawPrimitive
,
7610 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7611 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7612 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7613 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7614 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7615 IWineD3DDeviceImpl_DrawRectPatch
,
7616 IWineD3DDeviceImpl_DrawTriPatch
,
7617 IWineD3DDeviceImpl_DeletePatch
,
7618 IWineD3DDeviceImpl_ColorFill
,
7619 IWineD3DDeviceImpl_UpdateTexture
,
7620 IWineD3DDeviceImpl_UpdateSurface
,
7621 IWineD3DDeviceImpl_GetFrontBufferData
,
7622 /*** object tracking ***/
7623 IWineD3DDeviceImpl_ResourceReleased
,
7624 IWineD3DDeviceImpl_EnumResources
7627 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl
=
7629 /*** IUnknown methods ***/
7630 IWineD3DDeviceImpl_QueryInterface
,
7631 IWineD3DDeviceImpl_AddRef
,
7632 IWineD3DDeviceImpl_Release
,
7633 /*** IWineD3DDevice methods ***/
7634 IWineD3DDeviceImpl_GetParent
,
7635 /*** Creation methods**/
7636 IWineD3DDeviceImpl_CreateVertexBuffer
,
7637 IWineD3DDeviceImpl_CreateIndexBuffer
,
7638 IWineD3DDeviceImpl_CreateStateBlock
,
7639 IWineD3DDeviceImpl_CreateSurface
,
7640 IWineD3DDeviceImpl_CreateTexture
,
7641 IWineD3DDeviceImpl_CreateVolumeTexture
,
7642 IWineD3DDeviceImpl_CreateVolume
,
7643 IWineD3DDeviceImpl_CreateCubeTexture
,
7644 IWineD3DDeviceImpl_CreateQuery
,
7645 IWineD3DDeviceImpl_CreateSwapChain
,
7646 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7647 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7648 IWineD3DDeviceImpl_CreateVertexShader
,
7649 IWineD3DDeviceImpl_CreatePixelShader
,
7650 IWineD3DDeviceImpl_CreatePalette
,
7651 /*** Odd functions **/
7652 IWineD3DDeviceImpl_Init3D
,
7653 IWineD3DDeviceImpl_InitGDI
,
7654 IWineD3DDeviceImpl_Uninit3D
,
7655 IWineD3DDeviceImpl_UninitGDI
,
7656 IWineD3DDeviceImpl_SetMultithreaded
,
7657 IWineD3DDeviceImpl_EvictManagedResources
,
7658 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7659 IWineD3DDeviceImpl_GetBackBuffer
,
7660 IWineD3DDeviceImpl_GetCreationParameters
,
7661 IWineD3DDeviceImpl_GetDeviceCaps
,
7662 IWineD3DDeviceImpl_GetDirect3D
,
7663 IWineD3DDeviceImpl_GetDisplayMode
,
7664 IWineD3DDeviceImpl_SetDisplayMode
,
7665 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7666 IWineD3DDeviceImpl_GetRasterStatus
,
7667 IWineD3DDeviceImpl_GetSwapChain
,
7668 IWineD3DDeviceImpl_Reset
,
7669 IWineD3DDeviceImpl_SetDialogBoxMode
,
7670 IWineD3DDeviceImpl_SetCursorProperties
,
7671 IWineD3DDeviceImpl_SetCursorPosition
,
7672 IWineD3DDeviceImpl_ShowCursor
,
7673 IWineD3DDeviceImpl_TestCooperativeLevel
,
7674 /*** Getters and setters **/
7675 IWineD3DDeviceImpl_SetClipPlane
,
7676 IWineD3DDeviceImpl_GetClipPlane
,
7677 IWineD3DDeviceImpl_SetClipStatus
,
7678 IWineD3DDeviceImpl_GetClipStatus
,
7679 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7680 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7681 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7682 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7683 IWineD3DDeviceImpl_SetFVF
,
7684 IWineD3DDeviceImpl_GetFVF
,
7685 IWineD3DDeviceImpl_SetGammaRamp
,
7686 IWineD3DDeviceImpl_GetGammaRamp
,
7687 IWineD3DDeviceImpl_SetIndices
,
7688 IWineD3DDeviceImpl_GetIndices
,
7689 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7690 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7691 IWineD3DDeviceImpl_SetLight
,
7692 IWineD3DDeviceImpl_GetLight
,
7693 IWineD3DDeviceImpl_SetLightEnable
,
7694 IWineD3DDeviceImpl_GetLightEnable
,
7695 IWineD3DDeviceImpl_SetMaterial
,
7696 IWineD3DDeviceImpl_GetMaterial
,
7697 IWineD3DDeviceImpl_SetNPatchMode
,
7698 IWineD3DDeviceImpl_GetNPatchMode
,
7699 IWineD3DDeviceImpl_SetPaletteEntries
,
7700 IWineD3DDeviceImpl_GetPaletteEntries
,
7701 IWineD3DDeviceImpl_SetPixelShader
,
7702 IWineD3DDeviceImpl_GetPixelShader
,
7703 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7704 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7705 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7706 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7707 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst
,
7708 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7709 IWineD3DDeviceImpl_SetRenderState
,
7710 IWineD3DDeviceImpl_GetRenderState
,
7711 IWineD3DDeviceImpl_SetRenderTarget
,
7712 IWineD3DDeviceImpl_GetRenderTarget
,
7713 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7714 IWineD3DDeviceImpl_SetSamplerState
,
7715 IWineD3DDeviceImpl_GetSamplerState
,
7716 IWineD3DDeviceImpl_SetScissorRect
,
7717 IWineD3DDeviceImpl_GetScissorRect
,
7718 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7719 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7720 IWineD3DDeviceImpl_SetStreamSource
,
7721 IWineD3DDeviceImpl_GetStreamSource
,
7722 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7723 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7724 IWineD3DDeviceImpl_SetTexture
,
7725 IWineD3DDeviceImpl_GetTexture
,
7726 IWineD3DDeviceImpl_SetTextureStageState
,
7727 IWineD3DDeviceImpl_GetTextureStageState
,
7728 IWineD3DDeviceImpl_SetTransform
,
7729 IWineD3DDeviceImpl_GetTransform
,
7730 IWineD3DDeviceImpl_SetVertexDeclaration
,
7731 IWineD3DDeviceImpl_GetVertexDeclaration
,
7732 IWineD3DDeviceImpl_SetVertexShader
,
7733 IWineD3DDeviceImpl_GetVertexShader
,
7734 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7735 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7736 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7737 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7738 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst
,
7739 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7740 IWineD3DDeviceImpl_SetViewport
,
7741 IWineD3DDeviceImpl_GetViewport
,
7742 IWineD3DDeviceImpl_MultiplyTransform
,
7743 IWineD3DDeviceImpl_ValidateDevice
,
7744 IWineD3DDeviceImpl_ProcessVertices
,
7745 /*** State block ***/
7746 IWineD3DDeviceImpl_BeginStateBlock
,
7747 IWineD3DDeviceImpl_EndStateBlock
,
7748 /*** Scene management ***/
7749 IWineD3DDeviceImpl_BeginScene
,
7750 IWineD3DDeviceImpl_EndScene
,
7751 IWineD3DDeviceImpl_Present
,
7752 IWineD3DDeviceImpl_Clear
,
7754 IWineD3DDeviceImpl_DrawPrimitive
,
7755 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7756 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7757 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7758 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7759 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7760 IWineD3DDeviceImpl_DrawRectPatch
,
7761 IWineD3DDeviceImpl_DrawTriPatch
,
7762 IWineD3DDeviceImpl_DeletePatch
,
7763 IWineD3DDeviceImpl_ColorFill
,
7764 IWineD3DDeviceImpl_UpdateTexture
,
7765 IWineD3DDeviceImpl_UpdateSurface
,
7766 IWineD3DDeviceImpl_GetFrontBufferData
,
7767 /*** object tracking ***/
7768 IWineD3DDeviceImpl_ResourceReleased
,
7769 IWineD3DDeviceImpl_EnumResources
7772 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7773 WINED3DRS_ALPHABLENDENABLE
,
7774 WINED3DRS_ALPHAFUNC
,
7775 WINED3DRS_ALPHAREF
,
7776 WINED3DRS_ALPHATESTENABLE
,
7778 WINED3DRS_COLORWRITEENABLE
,
7779 WINED3DRS_DESTBLEND
,
7780 WINED3DRS_DITHERENABLE
,
7781 WINED3DRS_FILLMODE
,
7782 WINED3DRS_FOGDENSITY
,
7784 WINED3DRS_FOGSTART
,
7785 WINED3DRS_LASTPIXEL
,
7786 WINED3DRS_SHADEMODE
,
7787 WINED3DRS_SRCBLEND
,
7788 WINED3DRS_STENCILENABLE
,
7789 WINED3DRS_STENCILFAIL
,
7790 WINED3DRS_STENCILFUNC
,
7791 WINED3DRS_STENCILMASK
,
7792 WINED3DRS_STENCILPASS
,
7793 WINED3DRS_STENCILREF
,
7794 WINED3DRS_STENCILWRITEMASK
,
7795 WINED3DRS_STENCILZFAIL
,
7796 WINED3DRS_TEXTUREFACTOR
,
7807 WINED3DRS_ZWRITEENABLE
7810 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7811 WINED3DTSS_ADDRESSW
,
7812 WINED3DTSS_ALPHAARG0
,
7813 WINED3DTSS_ALPHAARG1
,
7814 WINED3DTSS_ALPHAARG2
,
7815 WINED3DTSS_ALPHAOP
,
7816 WINED3DTSS_BUMPENVLOFFSET
,
7817 WINED3DTSS_BUMPENVLSCALE
,
7818 WINED3DTSS_BUMPENVMAT00
,
7819 WINED3DTSS_BUMPENVMAT01
,
7820 WINED3DTSS_BUMPENVMAT10
,
7821 WINED3DTSS_BUMPENVMAT11
,
7822 WINED3DTSS_COLORARG0
,
7823 WINED3DTSS_COLORARG1
,
7824 WINED3DTSS_COLORARG2
,
7825 WINED3DTSS_COLOROP
,
7826 WINED3DTSS_RESULTARG
,
7827 WINED3DTSS_TEXCOORDINDEX
,
7828 WINED3DTSS_TEXTURETRANSFORMFLAGS
7831 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7832 WINED3DSAMP_ADDRESSU
,
7833 WINED3DSAMP_ADDRESSV
,
7834 WINED3DSAMP_ADDRESSW
,
7835 WINED3DSAMP_BORDERCOLOR
,
7836 WINED3DSAMP_MAGFILTER
,
7837 WINED3DSAMP_MINFILTER
,
7838 WINED3DSAMP_MIPFILTER
,
7839 WINED3DSAMP_MIPMAPLODBIAS
,
7840 WINED3DSAMP_MAXMIPLEVEL
,
7841 WINED3DSAMP_MAXANISOTROPY
,
7842 WINED3DSAMP_SRGBTEXTURE
,
7843 WINED3DSAMP_ELEMENTINDEX
7846 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7848 WINED3DRS_AMBIENTMATERIALSOURCE
,
7849 WINED3DRS_CLIPPING
,
7850 WINED3DRS_CLIPPLANEENABLE
,
7851 WINED3DRS_COLORVERTEX
,
7852 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7853 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7854 WINED3DRS_FOGDENSITY
,
7856 WINED3DRS_FOGSTART
,
7857 WINED3DRS_FOGTABLEMODE
,
7858 WINED3DRS_FOGVERTEXMODE
,
7859 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7860 WINED3DRS_LIGHTING
,
7861 WINED3DRS_LOCALVIEWER
,
7862 WINED3DRS_MULTISAMPLEANTIALIAS
,
7863 WINED3DRS_MULTISAMPLEMASK
,
7864 WINED3DRS_NORMALIZENORMALS
,
7865 WINED3DRS_PATCHEDGESTYLE
,
7866 WINED3DRS_POINTSCALE_A
,
7867 WINED3DRS_POINTSCALE_B
,
7868 WINED3DRS_POINTSCALE_C
,
7869 WINED3DRS_POINTSCALEENABLE
,
7870 WINED3DRS_POINTSIZE
,
7871 WINED3DRS_POINTSIZE_MAX
,
7872 WINED3DRS_POINTSIZE_MIN
,
7873 WINED3DRS_POINTSPRITEENABLE
,
7874 WINED3DRS_RANGEFOGENABLE
,
7875 WINED3DRS_SPECULARMATERIALSOURCE
,
7876 WINED3DRS_TWEENFACTOR
,
7877 WINED3DRS_VERTEXBLEND
,
7878 WINED3DRS_CULLMODE
,
7882 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7883 WINED3DTSS_TEXCOORDINDEX
,
7884 WINED3DTSS_TEXTURETRANSFORMFLAGS
7887 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7888 WINED3DSAMP_DMAPOFFSET
7891 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7892 DWORD rep
= This
->StateTable
[state
].representative
;
7896 WineD3DContext
*context
;
7899 for(i
= 0; i
< This
->numContexts
; i
++) {
7900 context
= This
->contexts
[i
];
7901 if(isStateDirty(context
, rep
)) continue;
7903 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7906 context
->isStateDirty
[idx
] |= (1 << shift
);
7910 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7911 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7912 /* The drawable size of a pbuffer render target is the current pbuffer size
7914 *width
= dev
->pbufferWidth
;
7915 *height
= dev
->pbufferHeight
;
7918 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7919 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7921 *width
= This
->pow2Width
;
7922 *height
= This
->pow2Height
;
7925 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7926 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7927 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7928 * current context's drawable, which is the size of the back buffer of the swapchain
7929 * the active context belongs to. The back buffer of the swapchain is stored as the
7930 * surface the context belongs to.
7932 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
7933 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;