2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
139 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
140 if (IsEqualGUID(riid
, &IID_IUnknown
)
141 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
142 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
143 IUnknown_AddRef(iface
);
148 return E_NOINTERFACE
;
151 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
152 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
153 ULONG refCount
= InterlockedIncrement(&This
->ref
);
155 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
159 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
161 ULONG refCount
= InterlockedDecrement(&This
->ref
);
163 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->src_fbo
));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->dst_fbo
));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This
->resources
)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
182 dumpResources(&This
->resources
);
185 if(This
->contexts
) ERR("Context array not freed!\n");
186 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
187 This
->haveHardwareCursor
= FALSE
;
189 IWineD3D_Release(This
->wineD3D
);
190 This
->wineD3D
= NULL
;
191 HeapFree(GetProcessHeap(), 0, This
);
192 TRACE("Freed device %p\n", This
);
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
202 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
203 *pParent
= This
->parent
;
204 IUnknown_AddRef(This
->parent
);
208 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
209 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
211 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
212 IWineD3DVertexBufferImpl
*object
;
213 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
214 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer
= NULL
;
220 return WINED3DERR_INVALIDCALL
;
221 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer
= NULL
;
227 return WINED3DERR_INVALIDCALL
;
230 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
232 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
233 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion
<= 7 && conv
) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
262 object
->Flags
|= VBFLAG_CREATEVBO
;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
268 GLenum error
, glUsage
;
269 TRACE("Creating VBO for Index Buffer %p\n", object
);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
282 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
283 error
= glGetError();
284 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
290 error
= glGetError();
291 if(error
!= GL_NO_ERROR
) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage
= GL_STATIC_DRAW_ARB
;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
301 error
= glGetError();
302 if(error
!= GL_NO_ERROR
) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
307 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
317 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
318 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
319 HANDLE
*sharedHandle
, IUnknown
*parent
) {
320 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
321 IWineD3DIndexBufferImpl
*object
;
322 TRACE("(%p) Creating index buffer\n", This
);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
327 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
328 CreateIndexBufferVBO(This
, object
);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
332 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
333 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
338 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
340 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
341 IWineD3DStateBlockImpl
*object
;
345 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
346 object
->blockType
= Type
;
348 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
349 list_init(&object
->lightMap
[i
]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type
== WINED3DSBT_INIT
) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
360 temp_result
= allocate_shader_constants(object
);
361 if (WINED3D_OK
!= temp_result
)
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This
->stateBlock
!= NULL
)
366 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
368 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
370 /* Reset the ref and type after kludging it */
371 object
->wineD3DDevice
= This
;
373 object
->blockType
= Type
;
375 TRACE("Updating changed flags appropriate for type %d\n", Type
);
377 if (Type
== WINED3DSBT_ALL
) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
382 /* Lights are not part of the changed / set structure */
383 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
385 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
386 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
387 light
->changed
= TRUE
;
388 light
->enabledChanged
= TRUE
;
391 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
392 object
->contained_render_states
[j
- 1] = j
;
394 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
397 object
->contained_transform_states
[j
- 1] = j
;
399 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
400 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
401 object
->contained_vs_consts_f
[j
] = j
;
403 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
404 for(j
= 0; j
< MAX_CONST_I
; j
++) {
405 object
->contained_vs_consts_i
[j
] = j
;
407 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
408 for(j
= 0; j
< MAX_CONST_B
; j
++) {
409 object
->contained_vs_consts_b
[j
] = j
;
411 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
412 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
413 object
->contained_ps_consts_f
[j
] = j
;
415 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
416 for(j
= 0; j
< MAX_CONST_I
; j
++) {
417 object
->contained_ps_consts_i
[j
] = j
;
419 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
420 for(j
= 0; j
< MAX_CONST_B
; j
++) {
421 object
->contained_ps_consts_b
[j
] = j
;
423 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
424 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
425 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
426 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
427 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
428 object
->num_contained_tss_states
++;
431 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
432 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
433 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
434 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
435 object
->num_contained_sampler_states
++;
439 for(i
= 0; i
< MAX_STREAMS
; i
++) {
440 if(object
->streamSource
[i
]) {
441 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
444 if(object
->pIndexData
) {
445 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
447 if(object
->vertexShader
) {
448 IWineD3DVertexShader_AddRef(object
->vertexShader
);
450 if(object
->pixelShader
) {
451 IWineD3DPixelShader_AddRef(object
->pixelShader
);
454 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
459 object
->changed
.pixelShader
= TRUE
;
461 /* Pixel Shader Constants */
462 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
463 object
->contained_ps_consts_f
[i
] = i
;
464 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
466 object
->num_contained_ps_consts_f
= GL_LIMITS(vshader_constantsF
);
467 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
468 object
->contained_ps_consts_b
[i
] = i
;
469 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
471 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
472 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
473 object
->contained_ps_consts_i
[i
] = i
;
474 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
476 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
478 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
479 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
480 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
482 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
483 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
484 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
485 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
486 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
487 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
488 object
->num_contained_tss_states
++;
491 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
492 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
493 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
494 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
495 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
496 object
->num_contained_sampler_states
++;
499 if(object
->pixelShader
) {
500 IWineD3DPixelShader_AddRef(object
->pixelShader
);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i
= 0; i
< MAX_STREAMS
; i
++) {
507 object
->streamSource
[i
] = NULL
;
509 object
->pIndexData
= NULL
;
510 object
->vertexShader
= NULL
;
512 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
517 object
->changed
.vertexShader
= TRUE
;
519 /* Vertex Shader Constants */
520 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
521 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
522 object
->contained_vs_consts_f
[i
] = i
;
524 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
525 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
526 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
527 object
->contained_vs_consts_b
[i
] = i
;
529 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
530 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
531 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
532 object
->contained_vs_consts_i
[i
] = i
;
534 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
535 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
536 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
537 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
539 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
540 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
541 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
542 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
543 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
544 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
545 object
->num_contained_tss_states
++;
548 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
549 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
550 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
551 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
552 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
553 object
->num_contained_sampler_states
++;
557 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
559 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
560 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
561 light
->changed
= TRUE
;
562 light
->enabledChanged
= TRUE
;
566 for(i
= 0; i
< MAX_STREAMS
; i
++) {
567 if(object
->streamSource
[i
]) {
568 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
571 if(object
->vertexShader
) {
572 IWineD3DVertexShader_AddRef(object
->vertexShader
);
574 object
->pIndexData
= NULL
;
575 object
->pixelShader
= NULL
;
577 FIXME("Unrecognized state block type %d\n", Type
);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
584 /* ************************************
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
593 ******************************** */
595 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,WINED3DRESOURCETYPE Type
, DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
,DWORD MultisampleQuality
, HANDLE
* pSharedHandle
, WINED3DSURFTYPE Impl
, IUnknown
*parent
) {
596 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
597 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size
= 1;
599 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, NULL
, NULL
);
600 TRACE("(%p) Create surface\n",This
);
602 /** FIXME: Check ranges on the inputs are valid
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
610 *******************************/
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality
> 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
626 MultisampleQuality
=0;
629 /** FIXME: Check that the format is supported
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
636 *********************************/
637 if (WINED3DFMT_UNKNOWN
== Format
) {
639 } else if (Format
== WINED3DFMT_DXT1
) {
640 /* DXT1 is half byte per pixel */
641 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
643 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
644 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
645 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
647 /* The pitch is a multiple of 4 bytes */
648 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
652 /** Create and initialise the surface resource **/
653 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
654 /* "Standalone" surface */
655 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
657 object
->currentDesc
.Width
= Width
;
658 object
->currentDesc
.Height
= Height
;
659 object
->currentDesc
.MultiSampleType
= MultiSample
;
660 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
661 object
->glDescription
.level
= Level
;
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 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
720 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
721 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
723 /* Look at the implementation and set the correct Vtable */
726 /* Check if a 3D adapter is available when creating gl surfaces */
728 ERR("OpenGL surfaces are not available without opengl\n");
729 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
730 HeapFree(GetProcessHeap(), 0, object
);
731 return WINED3DERR_NOTAVAILABLE
;
736 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
740 /* To be sure to catch this */
741 ERR("Unknown requested surface implementation %d!\n", Impl
);
742 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
743 return WINED3DERR_INVALIDCALL
;
746 list_init(&object
->renderbuffers
);
748 /* Call the private setup routine */
749 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
753 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
754 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
755 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
756 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
758 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
759 IWineD3DTextureImpl
*object
;
764 unsigned int pow2Width
;
765 unsigned int pow2Height
;
766 const GlPixelFormatDesc
*glDesc
;
767 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
769 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
770 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
771 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
773 /* TODO: It should only be possible to create textures for formats
774 that are reported as supported */
775 if (WINED3DFMT_UNKNOWN
>= Format
) {
776 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
777 return WINED3DERR_INVALIDCALL
;
780 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
781 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
782 object
->width
= Width
;
783 object
->height
= Height
;
785 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
786 object
->baseTexture
.minMipLookup
= &minMipLookup
;
787 object
->baseTexture
.magLookup
= &magLookup
;
789 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
790 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
793 /** Non-power2 support **/
794 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
798 /* Find the nearest pow2 match */
799 pow2Width
= pow2Height
= 1;
800 while (pow2Width
< Width
) pow2Width
<<= 1;
801 while (pow2Height
< Height
) pow2Height
<<= 1;
803 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
805 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
806 HeapFree(GetProcessHeap(), 0, object
);
808 return WINED3DERR_INVALIDCALL
;
815 /** FIXME: add support for real non-power-two if it's provided by the video card **/
816 /* Precalculated scaling for 'faked' non power of two texture coords.
817 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
818 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
819 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
821 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT
) && (Width
!= pow2Width
|| Height
!= pow2Height
)) {
822 object
->baseTexture
.pow2Matrix
[0] = 1.0;
823 object
->baseTexture
.pow2Matrix
[5] = 1.0;
824 object
->baseTexture
.pow2Matrix
[10] = 1.0;
825 object
->baseTexture
.pow2Matrix
[15] = 1.0;
826 object
->target
= GL_TEXTURE_2D
;
827 object
->cond_np2
= TRUE
;
830 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
831 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
832 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
834 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
835 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
836 object
->baseTexture
.pow2Matrix
[10] = 1.0;
837 object
->baseTexture
.pow2Matrix
[15] = 1.0;
838 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
839 object
->cond_np2
= TRUE
;
841 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
842 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
843 object
->baseTexture
.pow2Matrix
[10] = 1.0;
844 object
->baseTexture
.pow2Matrix
[15] = 1.0;
845 object
->target
= GL_TEXTURE_2D
;
846 object
->cond_np2
= FALSE
;
848 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
850 /* Calculate levels for mip mapping */
851 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
852 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
853 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL
;
857 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
858 return WINED3DERR_INVALIDCALL
;
860 object
->baseTexture
.levels
= 1;
861 } else if (Levels
== 0) {
862 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
863 object
->baseTexture
.levels
++;
866 while (tmpW
> 1 || tmpH
> 1) {
867 tmpW
= max(1, tmpW
>> 1);
868 tmpH
= max(1, tmpH
>> 1);
869 object
->baseTexture
.levels
++;
871 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
874 /* Generate all the surfaces */
877 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
879 /* use the callback to create the texture surface */
880 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
881 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
882 FIXME("Failed to create surface %p\n", object
);
884 object
->surfaces
[i
] = NULL
;
885 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
891 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
892 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
893 /* calculate the next mipmap level */
894 tmpW
= max(1, tmpW
>> 1);
895 tmpH
= max(1, tmpH
>> 1);
897 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
899 TRACE("(%p) : Created texture %p\n", This
, object
);
903 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
904 UINT Width
, UINT Height
, UINT Depth
,
905 UINT Levels
, DWORD Usage
,
906 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
907 IWineD3DVolumeTexture
**ppVolumeTexture
,
908 HANDLE
*pSharedHandle
, IUnknown
*parent
,
909 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
911 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
912 IWineD3DVolumeTextureImpl
*object
;
917 const GlPixelFormatDesc
*glDesc
;
919 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
921 /* TODO: It should only be possible to create textures for formats
922 that are reported as supported */
923 if (WINED3DFMT_UNKNOWN
>= Format
) {
924 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
925 return WINED3DERR_INVALIDCALL
;
927 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
928 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
929 return WINED3DERR_INVALIDCALL
;
932 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
933 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
935 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
936 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
938 object
->width
= Width
;
939 object
->height
= Height
;
940 object
->depth
= Depth
;
942 /* Is NP2 support for volumes needed? */
943 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
944 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
945 object
->baseTexture
.pow2Matrix
[10] = 1.0;
946 object
->baseTexture
.pow2Matrix
[15] = 1.0;
948 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
949 object
->baseTexture
.minMipLookup
= &minMipLookup
;
950 object
->baseTexture
.magLookup
= &magLookup
;
952 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
953 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
956 /* Calculate levels for mip mapping */
957 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
958 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
959 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
960 return WINED3DERR_INVALIDCALL
;
963 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
964 return WINED3DERR_INVALIDCALL
;
967 } else if (Levels
== 0) {
968 object
->baseTexture
.levels
++;
972 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
973 tmpW
= max(1, tmpW
>> 1);
974 tmpH
= max(1, tmpH
>> 1);
975 tmpD
= max(1, tmpD
>> 1);
976 object
->baseTexture
.levels
++;
978 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
981 /* Generate all the surfaces */
986 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
989 /* Create the volume */
990 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
991 &object
->volumes
[i
], pSharedHandle
);
994 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
995 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
996 *ppVolumeTexture
= NULL
;
1000 /* Set its container to this object */
1001 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1003 /* calculate the next mipmap level */
1004 tmpW
= max(1, tmpW
>> 1);
1005 tmpH
= max(1, tmpH
>> 1);
1006 tmpD
= max(1, tmpD
>> 1);
1008 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1010 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1011 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1015 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1016 UINT Width
, UINT Height
, UINT Depth
,
1018 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1019 IWineD3DVolume
** ppVolume
,
1020 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1022 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1023 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1024 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1026 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1027 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1028 return WINED3DERR_INVALIDCALL
;
1031 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1033 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1034 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1036 object
->currentDesc
.Width
= Width
;
1037 object
->currentDesc
.Height
= Height
;
1038 object
->currentDesc
.Depth
= Depth
;
1039 object
->bytesPerPixel
= formatDesc
->bpp
;
1041 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1042 object
->lockable
= TRUE
;
1043 object
->locked
= FALSE
;
1044 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1045 object
->dirty
= TRUE
;
1047 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1050 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1051 UINT Levels
, DWORD Usage
,
1052 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1053 IWineD3DCubeTexture
**ppCubeTexture
,
1054 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1055 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1057 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1058 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1062 unsigned int pow2EdgeLength
= EdgeLength
;
1063 const GlPixelFormatDesc
*glDesc
;
1064 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1066 /* TODO: It should only be possible to create textures for formats
1067 that are reported as supported */
1068 if (WINED3DFMT_UNKNOWN
>= Format
) {
1069 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1070 return WINED3DERR_INVALIDCALL
;
1073 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1074 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1075 return WINED3DERR_INVALIDCALL
;
1078 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1079 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1081 TRACE("(%p) Create Cube Texture\n", This
);
1083 /** Non-power2 support **/
1085 /* Find the nearest pow2 match */
1087 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1089 object
->edgeLength
= EdgeLength
;
1090 /* TODO: support for native non-power 2 */
1091 /* Precalculated scaling for 'faked' non power of two texture coords */
1092 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1093 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1094 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1095 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1097 if(glDesc
->Flags
& WINED3DFMT_FLAG_FILTERING
) {
1098 object
->baseTexture
.minMipLookup
= &minMipLookup
;
1099 object
->baseTexture
.magLookup
= &magLookup
;
1101 object
->baseTexture
.minMipLookup
= &minMipLookup_noFilter
;
1102 object
->baseTexture
.magLookup
= &magLookup_noFilter
;
1105 /* Calculate levels for mip mapping */
1106 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1107 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1108 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1109 HeapFree(GetProcessHeap(), 0, object
);
1110 *ppCubeTexture
= NULL
;
1112 return WINED3DERR_INVALIDCALL
;
1115 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1116 HeapFree(GetProcessHeap(), 0, object
);
1117 *ppCubeTexture
= NULL
;
1119 return WINED3DERR_INVALIDCALL
;
1122 } else if (Levels
== 0) {
1123 object
->baseTexture
.levels
++;
1126 tmpW
= max(1, tmpW
>> 1);
1127 object
->baseTexture
.levels
++;
1129 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1132 /* Generate all the surfaces */
1134 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1136 /* Create the 6 faces */
1137 for (j
= 0; j
< 6; j
++) {
1139 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1140 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1142 if(hr
!= WINED3D_OK
) {
1146 for (l
= 0; l
< j
; l
++) {
1147 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1149 for (k
= 0; k
< i
; k
++) {
1150 for (l
= 0; l
< 6; l
++) {
1151 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1155 FIXME("(%p) Failed to create surface\n",object
);
1156 HeapFree(GetProcessHeap(),0,object
);
1157 *ppCubeTexture
= NULL
;
1160 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1161 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1163 tmpW
= max(1, tmpW
>> 1);
1165 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1167 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1168 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1172 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1173 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1174 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1175 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1176 const IWineD3DQueryVtbl
*vtable
;
1178 /* Just a check to see if we support this type of query */
1180 case WINED3DQUERYTYPE_OCCLUSION
:
1181 TRACE("(%p) occlusion query\n", This
);
1182 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1185 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1187 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1190 case WINED3DQUERYTYPE_EVENT
:
1191 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1192 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1193 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1195 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1197 vtable
= &IWineD3DEventQuery_Vtbl
;
1201 case WINED3DQUERYTYPE_VCACHE
:
1202 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1203 case WINED3DQUERYTYPE_VERTEXSTATS
:
1204 case WINED3DQUERYTYPE_TIMESTAMP
:
1205 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1206 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1207 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1208 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1209 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1210 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1211 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1212 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1214 /* Use the base Query vtable until we have a special one for each query */
1215 vtable
= &IWineD3DQuery_Vtbl
;
1216 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1218 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1222 D3DCREATEOBJECTINSTANCE(object
, Query
)
1223 object
->lpVtbl
= vtable
;
1224 object
->type
= Type
;
1225 object
->state
= QUERY_CREATED
;
1226 /* allocated the 'extended' data based on the type of query requested */
1228 case WINED3DQUERYTYPE_OCCLUSION
:
1229 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1230 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1232 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1233 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1234 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1237 case WINED3DQUERYTYPE_EVENT
:
1238 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1239 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1241 if(GL_SUPPORT(APPLE_FENCE
)) {
1242 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1243 checkGLcall("glGenFencesAPPLE");
1244 } else if(GL_SUPPORT(NV_FENCE
)) {
1245 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1246 checkGLcall("glGenFencesNV");
1250 case WINED3DQUERYTYPE_VCACHE
:
1251 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1252 case WINED3DQUERYTYPE_VERTEXSTATS
:
1253 case WINED3DQUERYTYPE_TIMESTAMP
:
1254 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1255 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1256 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1257 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1258 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1259 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1260 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1261 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1263 object
->extendedData
= 0;
1264 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1266 TRACE("(%p) : Created Query %p\n", This
, object
);
1270 /*****************************************************************************
1271 * IWineD3DDeviceImpl_SetupFullscreenWindow
1273 * Helper function that modifies a HWND's Style and ExStyle for proper
1277 * iface: Pointer to the IWineD3DDevice interface
1278 * window: Window to setup
1280 *****************************************************************************/
1281 static LONG
fullscreen_style(LONG orig_style
) {
1282 LONG style
= orig_style
;
1283 style
&= ~WS_CAPTION
;
1284 style
&= ~WS_THICKFRAME
;
1286 /* Make sure the window is managed, otherwise we won't get keyboard input */
1287 style
|= WS_POPUP
| WS_SYSMENU
;
1292 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1293 LONG exStyle
= orig_exStyle
;
1295 /* Filter out window decorations */
1296 exStyle
&= ~WS_EX_WINDOWEDGE
;
1297 exStyle
&= ~WS_EX_CLIENTEDGE
;
1302 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1305 LONG style
, exStyle
;
1306 /* Don't do anything if an original style is stored.
1307 * That shouldn't happen
1309 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1310 if (This
->style
|| This
->exStyle
) {
1311 ERR("(%p): Want to change the window parameters of HWND %p, but "
1312 "another style is stored for restoration afterwards\n", This
, window
);
1315 /* Get the parameters and save them */
1316 style
= GetWindowLongW(window
, GWL_STYLE
);
1317 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1318 This
->style
= style
;
1319 This
->exStyle
= exStyle
;
1321 style
= fullscreen_style(style
);
1322 exStyle
= fullscreen_exStyle(exStyle
);
1324 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1325 This
->style
, This
->exStyle
, style
, exStyle
);
1327 SetWindowLongW(window
, GWL_STYLE
, style
);
1328 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1330 /* Inform the window about the update. */
1331 SetWindowPos(window
, HWND_TOP
, 0, 0,
1332 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1333 ShowWindow(window
, SW_NORMAL
);
1336 /*****************************************************************************
1337 * IWineD3DDeviceImpl_RestoreWindow
1339 * Helper function that restores a windows' properties when taking it out
1340 * of fullscreen mode
1343 * iface: Pointer to the IWineD3DDevice interface
1344 * window: Window to setup
1346 *****************************************************************************/
1347 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1348 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1349 LONG style
, exStyle
;
1351 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1352 * switch, do nothing
1354 if (!This
->style
&& !This
->exStyle
) return;
1356 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1357 This
, window
, This
->style
, This
->exStyle
);
1359 style
= GetWindowLongW(window
, GWL_STYLE
);
1360 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1362 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1363 * Some applications change it before calling Reset() when switching between windowed and
1364 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1366 if(style
== fullscreen_style(This
->style
) &&
1367 exStyle
== fullscreen_style(This
->exStyle
)) {
1368 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1369 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1372 /* Delete the old values */
1376 /* Inform the window about the update */
1377 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1378 0, 0, 0, 0, /* Pos, Size, ignored */
1379 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1382 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1383 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1385 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1386 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1387 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1390 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1391 HRESULT hr
= WINED3D_OK
;
1392 IUnknown
*bufferParent
;
1393 BOOL displaymode_set
= FALSE
;
1394 WINED3DDISPLAYMODE Mode
;
1395 const StaticPixelFormatDesc
*formatDesc
;
1397 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1399 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1400 * does a device hold a reference to a swap chain giving them a lifetime of the device
1401 * or does the swap chain notify the device of its destruction.
1402 *******************************/
1404 /* Check the params */
1405 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1406 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1407 return WINED3DERR_INVALIDCALL
;
1408 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1409 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");
1412 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1414 /*********************
1415 * Lookup the window Handle and the relating X window handle
1416 ********************/
1418 /* Setup hwnd we are using, plus which display this equates to */
1419 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1420 if (!object
->win_handle
) {
1421 object
->win_handle
= This
->createParms
.hFocusWindow
;
1423 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, object
->win_handle
);
1425 hDc
= GetDC(object
->win_handle
);
1426 TRACE("Using hDc %p\n", hDc
);
1429 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1430 return WINED3DERR_NOTAVAILABLE
;
1433 /* Get info on the current display setup */
1434 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1435 object
->orig_width
= Mode
.Width
;
1436 object
->orig_height
= Mode
.Height
;
1437 object
->orig_fmt
= Mode
.Format
;
1438 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1440 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1441 * then the corresponding dimension of the client area of the hDeviceWindow
1442 * (or the focus window, if hDeviceWindow is NULL) is taken.
1443 **********************/
1445 if (pPresentationParameters
->Windowed
&&
1446 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1447 (pPresentationParameters
->BackBufferHeight
== 0) ||
1448 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1451 GetClientRect(object
->win_handle
, &Rect
);
1453 if (pPresentationParameters
->BackBufferWidth
== 0) {
1454 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1455 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1457 if (pPresentationParameters
->BackBufferHeight
== 0) {
1458 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1459 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1461 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1462 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1463 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1467 /* Put the correct figures in the presentation parameters */
1468 TRACE("Copying across presentation parameters\n");
1469 object
->presentParms
= *pPresentationParameters
;
1471 TRACE("calling rendertarget CB\n");
1472 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1474 object
->presentParms
.BackBufferWidth
,
1475 object
->presentParms
.BackBufferHeight
,
1476 object
->presentParms
.BackBufferFormat
,
1477 object
->presentParms
.MultiSampleType
,
1478 object
->presentParms
.MultiSampleQuality
,
1479 TRUE
/* Lockable */,
1480 &object
->frontBuffer
,
1481 NULL
/* pShared (always null)*/);
1482 if (object
->frontBuffer
!= NULL
) {
1483 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1484 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1486 ERR("Failed to create the front buffer\n");
1490 /*********************
1491 * Windowed / Fullscreen
1492 *******************/
1495 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1496 * so we should really check to see if there is a fullscreen swapchain already
1497 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1498 **************************************/
1500 if (!pPresentationParameters
->Windowed
) {
1501 WINED3DDISPLAYMODE mode
;
1504 /* Change the display settings */
1505 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1506 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1507 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1508 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1510 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1511 displaymode_set
= TRUE
;
1512 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1516 * Create an opengl context for the display visual
1517 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1518 * use different properties after that point in time. FIXME: How to handle when requested format
1519 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1520 * it chooses is identical to the one already being used!
1521 **********************************/
1522 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1524 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1525 if(!object
->context
)
1526 return E_OUTOFMEMORY
;
1527 object
->num_contexts
= 1;
1529 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1530 if (!object
->context
[0]) {
1531 ERR("Failed to create a new context\n");
1532 hr
= WINED3DERR_NOTAVAILABLE
;
1535 TRACE("Context created (HWND=%p, glContext=%p)\n",
1536 object
->win_handle
, object
->context
[0]->glCtx
);
1539 /*********************
1540 * Create the back, front and stencil buffers
1541 *******************/
1542 if(object
->presentParms
.BackBufferCount
> 0) {
1545 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1546 if(!object
->backBuffer
) {
1547 ERR("Out of memory\n");
1552 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1553 TRACE("calling rendertarget CB\n");
1554 hr
= D3DCB_CreateRenderTarget(This
->parent
,
1556 object
->presentParms
.BackBufferWidth
,
1557 object
->presentParms
.BackBufferHeight
,
1558 object
->presentParms
.BackBufferFormat
,
1559 object
->presentParms
.MultiSampleType
,
1560 object
->presentParms
.MultiSampleQuality
,
1561 TRUE
/* Lockable */,
1562 &object
->backBuffer
[i
],
1563 NULL
/* pShared (always null)*/);
1564 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1565 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1567 ERR("Cannot create new back buffer\n");
1571 glDrawBuffer(GL_BACK
);
1572 checkGLcall("glDrawBuffer(GL_BACK)");
1576 object
->backBuffer
= NULL
;
1578 /* Single buffering - draw to front buffer */
1580 glDrawBuffer(GL_FRONT
);
1581 checkGLcall("glDrawBuffer(GL_FRONT)");
1585 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1586 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1587 TRACE("Creating depth stencil buffer\n");
1588 if (This
->auto_depth_stencil_buffer
== NULL
) {
1589 hr
= D3DCB_CreateDepthStencil(This
->parent
,
1591 object
->presentParms
.BackBufferWidth
,
1592 object
->presentParms
.BackBufferHeight
,
1593 object
->presentParms
.AutoDepthStencilFormat
,
1594 object
->presentParms
.MultiSampleType
,
1595 object
->presentParms
.MultiSampleQuality
,
1596 FALSE
/* FIXME: Discard */,
1597 &This
->auto_depth_stencil_buffer
,
1598 NULL
/* pShared (always null)*/ );
1599 if (This
->auto_depth_stencil_buffer
!= NULL
)
1600 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1603 /** TODO: A check on width, height and multisample types
1604 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1605 ****************************/
1606 object
->wantsDepthStencilBuffer
= TRUE
;
1608 object
->wantsDepthStencilBuffer
= FALSE
;
1611 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1613 TRACE("Created swapchain %p\n", object
);
1614 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1618 if (displaymode_set
) {
1622 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1625 /* Change the display settings */
1626 memset(&devmode
, 0, sizeof(devmode
));
1627 devmode
.dmSize
= sizeof(devmode
);
1628 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1629 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1630 devmode
.dmPelsWidth
= object
->orig_width
;
1631 devmode
.dmPelsHeight
= object
->orig_height
;
1632 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1635 if (object
->backBuffer
) {
1637 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1638 if(object
->backBuffer
[i
]) {
1639 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1640 IUnknown_Release(bufferParent
); /* once for the get parent */
1641 if (IUnknown_Release(bufferParent
) > 0) {
1642 FIXME("(%p) Something's still holding the back buffer\n",This
);
1646 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1647 object
->backBuffer
= NULL
;
1649 if(object
->context
[0])
1650 DestroyContext(This
, object
->context
[0]);
1651 if(object
->frontBuffer
) {
1652 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1653 IUnknown_Release(bufferParent
); /* once for the get parent */
1654 if (IUnknown_Release(bufferParent
) > 0) {
1655 FIXME("(%p) Something's still holding the front buffer\n",This
);
1658 HeapFree(GetProcessHeap(), 0, object
);
1662 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1663 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1664 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1665 TRACE("(%p)\n", This
);
1667 return This
->NumberOfSwapChains
;
1670 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1671 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1672 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1674 if(iSwapChain
< This
->NumberOfSwapChains
) {
1675 *pSwapChain
= This
->swapchains
[iSwapChain
];
1676 IWineD3DSwapChain_AddRef(*pSwapChain
);
1677 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1680 TRACE("Swapchain out of range\n");
1682 return WINED3DERR_INVALIDCALL
;
1687 * Vertex Declaration
1689 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1690 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
1691 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1692 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1693 HRESULT hr
= WINED3D_OK
;
1695 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1696 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1698 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1700 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1702 *ppVertexDeclaration
= NULL
;
1703 HeapFree(GetProcessHeap(), 0, object
);
1709 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1710 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1712 unsigned int idx
, idx2
;
1713 unsigned int offset
;
1714 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1715 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1716 BOOL has_blend_idx
= has_blend
&&
1717 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1718 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1719 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1720 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1721 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1722 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1723 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1725 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1726 DWORD texcoords
= (fvf
& 0x00FF0000) >> 16;
1728 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1729 WINED3DVERTEXELEMENT
*elements
= NULL
;
1732 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1733 if (has_blend_idx
) num_blends
--;
1735 /* Compute declaration size */
1736 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1737 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1739 /* convert the declaration */
1740 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1744 elements
[size
-1] = end_element
;
1747 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1748 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1749 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1752 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1753 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1755 elements
[idx
].UsageIndex
= 0;
1758 if (has_blend
&& (num_blends
> 0)) {
1759 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1760 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1762 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1763 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1764 elements
[idx
].UsageIndex
= 0;
1767 if (has_blend_idx
) {
1768 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1769 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1770 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1771 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1772 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1774 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1775 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1776 elements
[idx
].UsageIndex
= 0;
1780 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1781 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1782 elements
[idx
].UsageIndex
= 0;
1786 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1787 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1788 elements
[idx
].UsageIndex
= 0;
1792 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1793 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1794 elements
[idx
].UsageIndex
= 0;
1798 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1799 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1800 elements
[idx
].UsageIndex
= 1;
1803 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1804 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1805 switch (numcoords
) {
1806 case WINED3DFVF_TEXTUREFORMAT1
:
1807 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1809 case WINED3DFVF_TEXTUREFORMAT2
:
1810 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1812 case WINED3DFVF_TEXTUREFORMAT3
:
1813 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1815 case WINED3DFVF_TEXTUREFORMAT4
:
1816 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1819 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1820 elements
[idx
].UsageIndex
= idx2
;
1824 /* Now compute offsets, and initialize the rest of the fields */
1825 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1826 elements
[idx
].Stream
= 0;
1827 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1828 elements
[idx
].Offset
= offset
;
1829 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1832 *ppVertexElements
= elements
;
1836 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1837 WINED3DVERTEXELEMENT
* elements
= NULL
;
1838 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1842 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1843 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1845 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1846 HeapFree(GetProcessHeap(), 0, elements
);
1847 if (hr
!= S_OK
) return hr
;
1852 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1853 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1854 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1855 HRESULT hr
= WINED3D_OK
;
1856 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1857 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1859 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1861 if (vertex_declaration
) {
1862 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1865 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1867 if (WINED3D_OK
!= hr
) {
1868 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1869 IWineD3DVertexShader_Release(*ppVertexShader
);
1870 return WINED3DERR_INVALIDCALL
;
1872 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1877 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1878 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1879 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1880 HRESULT hr
= WINED3D_OK
;
1882 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1883 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1884 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1885 if (WINED3D_OK
== hr
) {
1886 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1887 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
1889 WARN("(%p) : Failed to create pixel shader\n", This
);
1895 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1897 IWineD3DPaletteImpl
*object
;
1899 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1901 /* Create the new object */
1902 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1904 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1905 return E_OUTOFMEMORY
;
1908 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1910 object
->Flags
= Flags
;
1911 object
->parent
= Parent
;
1912 object
->wineD3DDevice
= This
;
1913 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1915 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1918 HeapFree( GetProcessHeap(), 0, object
);
1919 return E_OUTOFMEMORY
;
1922 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1924 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1928 *Palette
= (IWineD3DPalette
*) object
;
1933 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1937 HDC dcb
= NULL
, dcs
= NULL
;
1938 WINEDDCOLORKEY colorkey
;
1940 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1943 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1944 dcb
= CreateCompatibleDC(NULL
);
1946 SelectObject(dcb
, hbm
);
1950 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1951 * couldn't be loaded
1953 memset(&bm
, 0, sizeof(bm
));
1958 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1959 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1960 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1962 ERR("Wine logo requested, but failed to create surface\n");
1967 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1968 if(FAILED(hr
)) goto out
;
1969 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1970 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1972 colorkey
.dwColorSpaceLowValue
= 0;
1973 colorkey
.dwColorSpaceHighValue
= 0;
1974 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1976 /* Fill the surface with a white color to show that wined3d is there */
1977 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1990 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
1992 /* Under DirectX you can have texture stage operations even if no texture is
1993 bound, whereas opengl will only do texture operations when a valid texture is
1994 bound. We emulate this by creating dummy textures and binding them to each
1995 texture stage, but disable all stages by default. Hence if a stage is enabled
1996 then the default texture will kick in until replaced by a SetTexture call */
1999 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2000 /* The dummy texture does not have client storage backing */
2001 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2002 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2004 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2005 GLubyte white
= 255;
2007 /* Make appropriate texture active */
2008 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2009 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2010 checkGLcall("glActiveTextureARB");
2012 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2015 /* Generate an opengl texture name */
2016 glGenTextures(1, &This
->dummyTextureName
[i
]);
2017 checkGLcall("glGenTextures");
2018 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2020 /* Generate a dummy 2d texture (not using 1d because they cause many
2021 * DRI drivers fall back to sw) */
2022 This
->stateBlock
->textureDimensions
[i
] = GL_TEXTURE_2D
;
2023 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2024 checkGLcall("glBindTexture");
2026 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2027 checkGLcall("glTexImage2D");
2029 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2030 /* Reenable because if supported it is enabled by default */
2031 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2032 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2038 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2040 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2045 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
2046 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2047 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2049 /* TODO: Test if OpenGL is compiled in and loaded */
2051 TRACE("(%p) : Creating stateblock\n", This
);
2052 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2053 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2055 (IWineD3DStateBlock
**)&This
->stateBlock
,
2057 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2058 WARN("Failed to create stateblock\n");
2061 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2062 This
->updateStateBlock
= This
->stateBlock
;
2063 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2065 hr
= allocate_shader_constants(This
->updateStateBlock
);
2066 if (WINED3D_OK
!= hr
) {
2070 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2071 This
->fbo_color_attachments
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2072 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2074 This
->NumberOfPalettes
= 1;
2075 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
2076 if(!This
->palettes
|| !This
->render_targets
|| !This
->fbo_color_attachments
|| !This
->draw_buffers
) {
2077 ERR("Out of memory!\n");
2080 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2081 if(!This
->palettes
[0]) {
2082 ERR("Out of memory!\n");
2085 for (i
= 0; i
< 256; ++i
) {
2086 This
->palettes
[0][i
].peRed
= 0xFF;
2087 This
->palettes
[0][i
].peGreen
= 0xFF;
2088 This
->palettes
[0][i
].peBlue
= 0xFF;
2089 This
->palettes
[0][i
].peFlags
= 0xFF;
2091 This
->currentPalette
= 0;
2093 /* Initialize the texture unit mapping to a 1:1 mapping */
2094 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2095 if (state
< GL_LIMITS(fragment_samplers
)) {
2096 This
->texUnitMap
[state
] = state
;
2097 This
->rev_tex_unit_map
[state
] = state
;
2099 This
->texUnitMap
[state
] = -1;
2100 This
->rev_tex_unit_map
[state
] = -1;
2104 /* Setup the implicit swapchain */
2105 TRACE("Creating implicit swapchain\n");
2106 hr
=D3DCB_CreateAdditionalSwapChain(This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2107 if (FAILED(hr
) || !swapchain
) {
2108 WARN("Failed to create implicit swapchain\n");
2112 This
->NumberOfSwapChains
= 1;
2113 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2114 if(!This
->swapchains
) {
2115 ERR("Out of memory!\n");
2118 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2120 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2121 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2122 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2123 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2126 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2127 This
->render_targets
[0] = swapchain
->frontBuffer
;
2128 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2130 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2131 This
->activeContext
= swapchain
->context
[0];
2132 This
->lastThread
= GetCurrentThreadId();
2134 /* Depth Stencil support */
2135 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2136 if (NULL
!= This
->stencilBufferTarget
) {
2137 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2140 hr
= This
->shader_backend
->shader_alloc_private(iface
);
2142 TRACE("Shader private data couldn't be allocated\n");
2145 hr
= This
->frag_pipe
->alloc_private(iface
);
2147 TRACE("Fragment pipeline private data couldn't be allocated\n");
2151 /* Set up some starting GL setup */
2153 /* Setup all the devices defaults */
2154 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2155 create_dummy_textures(This
);
2160 IWineD3DImpl_CheckGraphicsMemory();
2163 { /* Set a default viewport */
2167 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2168 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2171 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2174 /* Initialize the current view state */
2175 This
->view_ident
= 1;
2176 This
->contexts
[0]->last_was_rhw
= 0;
2177 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2178 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2180 switch(wined3d_settings
.offscreen_rendering_mode
) {
2183 This
->offscreenBuffer
= GL_BACK
;
2186 case ORM_BACKBUFFER
:
2188 if(This
->activeContext
->aux_buffers
> 0) {
2189 TRACE("Using auxilliary buffer for offscreen rendering\n");
2190 This
->offscreenBuffer
= GL_AUX0
;
2192 TRACE("Using back buffer for offscreen rendering\n");
2193 This
->offscreenBuffer
= GL_BACK
;
2198 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2201 /* Clear the screen */
2202 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2203 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2206 This
->d3d_initialized
= TRUE
;
2208 if(wined3d_settings
.logo
) {
2209 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2211 This
->highest_dirty_ps_const
= 0;
2212 This
->highest_dirty_vs_const
= 0;
2216 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2217 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2218 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2219 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2220 This
->NumberOfSwapChains
= 0;
2221 if(This
->palettes
) {
2222 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2223 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2225 This
->NumberOfPalettes
= 0;
2227 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2229 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2230 if(This
->stateBlock
) {
2231 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2232 This
->stateBlock
= NULL
;
2234 This
->shader_backend
->shader_free_private(iface
);
2235 This
->frag_pipe
->free_private(iface
);
2239 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2240 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2243 TRACE("(%p)\n", This
);
2245 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2247 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2248 * it was created. Thus make sure a context is active for the glDelete* calls
2250 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2252 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2254 TRACE("Deleting high order patches\n");
2255 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2256 struct list
*e1
, *e2
;
2257 struct WineD3DRectPatch
*patch
;
2258 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2259 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2260 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2264 /* Delete the palette conversion shader if it is around */
2265 if(This
->paletteConversionShader
) {
2267 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2269 This
->paletteConversionShader
= 0;
2272 /* Delete the pbuffer context if there is any */
2273 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2275 /* Delete the mouse cursor texture */
2276 if(This
->cursorTexture
) {
2278 glDeleteTextures(1, &This
->cursorTexture
);
2280 This
->cursorTexture
= 0;
2283 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2284 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2286 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2287 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2290 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2291 * private data, it might contain opengl pointers
2293 if(This
->depth_blt_texture
) {
2294 glDeleteTextures(1, &This
->depth_blt_texture
);
2295 This
->depth_blt_texture
= 0;
2297 if (This
->depth_blt_rb
) {
2298 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2299 This
->depth_blt_rb
= 0;
2300 This
->depth_blt_rb_w
= 0;
2301 This
->depth_blt_rb_h
= 0;
2304 /* Release the update stateblock */
2305 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2306 if(This
->updateStateBlock
!= This
->stateBlock
)
2307 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2309 This
->updateStateBlock
= NULL
;
2311 { /* because were not doing proper internal refcounts releasing the primary state block
2312 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2313 to set this->stateBlock = NULL; first */
2314 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2315 This
->stateBlock
= NULL
;
2317 /* Release the stateblock */
2318 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2319 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2323 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2324 This
->shader_backend
->shader_free_private(iface
);
2325 This
->frag_pipe
->free_private(iface
);
2327 /* Release the buffers (with sanity checks)*/
2328 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2329 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2330 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2331 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2333 This
->stencilBufferTarget
= NULL
;
2335 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2336 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2337 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2339 TRACE("Setting rendertarget to NULL\n");
2340 This
->render_targets
[0] = NULL
;
2342 if (This
->auto_depth_stencil_buffer
) {
2343 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2344 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2346 This
->auto_depth_stencil_buffer
= NULL
;
2349 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2350 TRACE("Releasing the implicit swapchain %d\n", i
);
2351 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2352 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2356 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2357 This
->swapchains
= NULL
;
2358 This
->NumberOfSwapChains
= 0;
2360 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2361 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2362 This
->palettes
= NULL
;
2363 This
->NumberOfPalettes
= 0;
2365 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2366 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2367 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2368 This
->render_targets
= NULL
;
2369 This
->fbo_color_attachments
= NULL
;
2370 This
->draw_buffers
= NULL
;
2372 This
->d3d_initialized
= FALSE
;
2376 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2377 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2378 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2380 /* Setup the window for fullscreen mode */
2381 if(fullscreen
&& !This
->ddraw_fullscreen
) {
2382 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
2383 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
2384 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
2387 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2388 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2389 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2392 This
->ddraw_fullscreen
= fullscreen
;
2395 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2396 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2397 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2399 * There is no way to deactivate thread safety once it is enabled.
2401 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2402 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2404 /*For now just store the flag(needed in case of ddraw) */
2405 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2410 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2412 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2414 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2417 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2419 /* Resize the screen even without a window:
2420 * The app could have unset it with SetCooperativeLevel, but not called
2421 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2422 * but we don't have any hwnd
2425 memset(&devmode
, 0, sizeof(devmode
));
2426 devmode
.dmSize
= sizeof(devmode
);
2427 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2428 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2429 devmode
.dmPelsWidth
= pMode
->Width
;
2430 devmode
.dmPelsHeight
= pMode
->Height
;
2432 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2433 if (pMode
->RefreshRate
!= 0) {
2434 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2437 /* Only change the mode if necessary */
2438 if( (This
->ddraw_width
== pMode
->Width
) &&
2439 (This
->ddraw_height
== pMode
->Height
) &&
2440 (This
->ddraw_format
== pMode
->Format
) &&
2441 (pMode
->RefreshRate
== 0) ) {
2445 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2446 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2447 if(devmode
.dmDisplayFrequency
!= 0) {
2448 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2449 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2450 devmode
.dmDisplayFrequency
= 0;
2451 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2453 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2454 return WINED3DERR_NOTAVAILABLE
;
2458 /* Store the new values */
2459 This
->ddraw_width
= pMode
->Width
;
2460 This
->ddraw_height
= pMode
->Height
;
2461 This
->ddraw_format
= pMode
->Format
;
2463 /* Only do this with a window of course, and only if we're fullscreened */
2464 if(This
->ddraw_window
&& This
->ddraw_fullscreen
)
2465 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2467 /* And finally clip mouse to our screen */
2468 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2469 ClipCursor(&clip_rc
);
2474 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2475 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2476 *ppD3D
= This
->wineD3D
;
2477 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2478 IWineD3D_AddRef(*ppD3D
);
2482 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2483 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2485 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2486 (This
->adapter
->TextureRam
/(1024*1024)),
2487 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2488 /* return simulated texture memory left */
2489 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2497 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2498 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2500 /* Update the current state block */
2501 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2503 if(This
->updateStateBlock
->fvf
== fvf
) {
2504 TRACE("Application is setting the old fvf over, nothing to do\n");
2508 This
->updateStateBlock
->fvf
= fvf
;
2509 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2510 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2515 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2516 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2517 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2518 *pfvf
= This
->stateBlock
->fvf
;
2523 * Get / Set Stream Source
2525 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2526 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2527 IWineD3DVertexBuffer
*oldSrc
;
2529 if (StreamNumber
>= MAX_STREAMS
) {
2530 WARN("Stream out of range %d\n", StreamNumber
);
2531 return WINED3DERR_INVALIDCALL
;
2532 } else if(OffsetInBytes
& 0x3) {
2533 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2534 return WINED3DERR_INVALIDCALL
;
2537 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2538 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2540 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2542 if(oldSrc
== pStreamData
&&
2543 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2544 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2545 TRACE("Application is setting the old values over, nothing to do\n");
2549 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2551 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2552 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2555 /* Handle recording of state blocks */
2556 if (This
->isRecordingState
) {
2557 TRACE("Recording... not performing anything\n");
2558 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2559 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2563 /* Need to do a getParent and pass the references up */
2564 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2565 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2566 so for now, just count internally */
2567 if (pStreamData
!= NULL
) {
2568 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2569 InterlockedIncrement(&vbImpl
->bindCount
);
2570 IWineD3DVertexBuffer_AddRef(pStreamData
);
2572 if (oldSrc
!= NULL
) {
2573 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2574 IWineD3DVertexBuffer_Release(oldSrc
);
2577 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2582 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2583 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2585 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2586 This
->stateBlock
->streamSource
[StreamNumber
],
2587 This
->stateBlock
->streamOffset
[StreamNumber
],
2588 This
->stateBlock
->streamStride
[StreamNumber
]);
2590 if (StreamNumber
>= MAX_STREAMS
) {
2591 WARN("Stream out of range %d\n", StreamNumber
);
2592 return WINED3DERR_INVALIDCALL
;
2594 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2595 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2597 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2600 if (*pStream
!= NULL
) {
2601 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2606 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2607 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2608 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2609 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2611 /* Verify input at least in d3d9 this is invalid*/
2612 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2613 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2614 return WINED3DERR_INVALIDCALL
;
2616 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2617 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2618 return WINED3DERR_INVALIDCALL
;
2621 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2622 return WINED3DERR_INVALIDCALL
;
2625 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2626 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2628 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2629 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2631 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2632 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2633 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2639 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2640 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2642 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2643 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2645 TRACE("(%p) : returning %d\n", This
, *Divider
);
2651 * Get / Set & Multiply Transform
2653 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2654 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2656 /* Most of this routine, comments included copied from ddraw tree initially: */
2657 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2659 /* Handle recording of state blocks */
2660 if (This
->isRecordingState
) {
2661 TRACE("Recording... not performing anything\n");
2662 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2663 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2668 * If the new matrix is the same as the current one,
2669 * we cut off any further processing. this seems to be a reasonable
2670 * optimization because as was noticed, some apps (warcraft3 for example)
2671 * tend towards setting the same matrix repeatedly for some reason.
2673 * From here on we assume that the new matrix is different, wherever it matters.
2675 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2676 TRACE("The app is setting the same matrix over again\n");
2679 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2683 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2684 where ViewMat = Camera space, WorldMat = world space.
2686 In OpenGL, camera and world space is combined into GL_MODELVIEW
2687 matrix. The Projection matrix stay projection matrix.
2690 /* Capture the times we can just ignore the change for now */
2691 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2692 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2693 /* Handled by the state manager */
2696 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2700 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2701 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2702 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2703 *pMatrix
= This
->stateBlock
->transforms
[State
];
2707 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2708 WINED3DMATRIX
*mat
= NULL
;
2711 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2712 * below means it will be recorded in a state block change, but it
2713 * works regardless where it is recorded.
2714 * If this is found to be wrong, change to StateBlock.
2716 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2717 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2719 if (State
< HIGHEST_TRANSFORMSTATE
)
2721 mat
= &This
->updateStateBlock
->transforms
[State
];
2723 FIXME("Unhandled transform state!!\n");
2726 multiply_matrix(&temp
, mat
, pMatrix
);
2728 /* Apply change via set transform - will reapply to eg. lights this way */
2729 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2735 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2736 you can reference any indexes you want as long as that number max are enabled at any
2737 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2738 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2739 but when recording, just build a chain pretty much of commands to be replayed. */
2741 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2743 PLIGHTINFOEL
*object
= NULL
;
2744 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2747 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2748 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2750 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2754 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2755 return WINED3DERR_INVALIDCALL
;
2758 switch(pLight
->Type
) {
2759 case WINED3DLIGHT_POINT
:
2760 case WINED3DLIGHT_SPOT
:
2761 case WINED3DLIGHT_PARALLELPOINT
:
2762 case WINED3DLIGHT_GLSPOT
:
2763 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2766 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2767 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2768 return WINED3DERR_INVALIDCALL
;
2772 case WINED3DLIGHT_DIRECTIONAL
:
2773 /* Ignores attenuation */
2777 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2778 return WINED3DERR_INVALIDCALL
;
2781 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2782 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2783 if(object
->OriginalIndex
== Index
) break;
2788 TRACE("Adding new light\n");
2789 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2791 ERR("Out of memory error when allocating a light\n");
2792 return E_OUTOFMEMORY
;
2794 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2795 object
->glIndex
= -1;
2796 object
->OriginalIndex
= Index
;
2797 object
->changed
= TRUE
;
2800 /* Initialize the object */
2801 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
,
2802 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2803 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2804 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2805 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2806 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2807 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2809 /* Save away the information */
2810 object
->OriginalParms
= *pLight
;
2812 switch (pLight
->Type
) {
2813 case WINED3DLIGHT_POINT
:
2815 object
->lightPosn
[0] = pLight
->Position
.x
;
2816 object
->lightPosn
[1] = pLight
->Position
.y
;
2817 object
->lightPosn
[2] = pLight
->Position
.z
;
2818 object
->lightPosn
[3] = 1.0f
;
2819 object
->cutoff
= 180.0f
;
2823 case WINED3DLIGHT_DIRECTIONAL
:
2825 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2826 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2827 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2828 object
->lightPosn
[3] = 0.0;
2829 object
->exponent
= 0.0f
;
2830 object
->cutoff
= 180.0f
;
2833 case WINED3DLIGHT_SPOT
:
2835 object
->lightPosn
[0] = pLight
->Position
.x
;
2836 object
->lightPosn
[1] = pLight
->Position
.y
;
2837 object
->lightPosn
[2] = pLight
->Position
.z
;
2838 object
->lightPosn
[3] = 1.0;
2841 object
->lightDirn
[0] = pLight
->Direction
.x
;
2842 object
->lightDirn
[1] = pLight
->Direction
.y
;
2843 object
->lightDirn
[2] = pLight
->Direction
.z
;
2844 object
->lightDirn
[3] = 1.0;
2847 * opengl-ish and d3d-ish spot lights use too different models for the
2848 * light "intensity" as a function of the angle towards the main light direction,
2849 * so we only can approximate very roughly.
2850 * however spot lights are rather rarely used in games (if ever used at all).
2851 * furthermore if still used, probably nobody pays attention to such details.
2853 if (pLight
->Falloff
== 0) {
2854 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2855 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2856 * will always be 1.0 for both of them, and we don't have to care for the
2857 * rest of the rather complex calculation
2859 object
->exponent
= 0;
2861 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2862 if (rho
< 0.0001) rho
= 0.0001f
;
2863 object
->exponent
= -0.3/log(cos(rho
/2));
2865 if (object
->exponent
> 128.0) {
2866 object
->exponent
= 128.0;
2868 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2874 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2877 /* Update the live definitions if the light is currently assigned a glIndex */
2878 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2879 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2884 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2885 PLIGHTINFOEL
*lightInfo
= NULL
;
2886 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2887 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2889 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2891 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2892 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2893 if(lightInfo
->OriginalIndex
== Index
) break;
2897 if (lightInfo
== NULL
) {
2898 TRACE("Light information requested but light not defined\n");
2899 return WINED3DERR_INVALIDCALL
;
2902 *pLight
= lightInfo
->OriginalParms
;
2907 * Get / Set Light Enable
2908 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2910 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2911 PLIGHTINFOEL
*lightInfo
= NULL
;
2912 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2913 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2915 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2917 /* Tests show true = 128...not clear why */
2918 Enable
= Enable
? 128: 0;
2920 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2921 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2922 if(lightInfo
->OriginalIndex
== Index
) break;
2925 TRACE("Found light: %p\n", lightInfo
);
2927 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2928 if (lightInfo
== NULL
) {
2930 TRACE("Light enabled requested but light not defined, so defining one!\n");
2931 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2933 /* Search for it again! Should be fairly quick as near head of list */
2934 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2935 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2936 if(lightInfo
->OriginalIndex
== Index
) break;
2939 if (lightInfo
== NULL
) {
2940 FIXME("Adding default lights has failed dismally\n");
2941 return WINED3DERR_INVALIDCALL
;
2945 lightInfo
->enabledChanged
= TRUE
;
2947 if(lightInfo
->glIndex
!= -1) {
2948 if(!This
->isRecordingState
) {
2949 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2952 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2953 lightInfo
->glIndex
= -1;
2955 TRACE("Light already disabled, nothing to do\n");
2957 lightInfo
->enabled
= FALSE
;
2959 lightInfo
->enabled
= TRUE
;
2960 if (lightInfo
->glIndex
!= -1) {
2962 TRACE("Nothing to do as light was enabled\n");
2965 /* Find a free gl light */
2966 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2967 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2968 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2969 lightInfo
->glIndex
= i
;
2973 if(lightInfo
->glIndex
== -1) {
2974 /* Our tests show that Windows returns D3D_OK in this situation, even with
2975 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2976 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2977 * as well for those lights.
2979 * TODO: Test how this affects rendering
2981 FIXME("Too many concurrently active lights\n");
2985 /* i == lightInfo->glIndex */
2986 if(!This
->isRecordingState
) {
2987 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2995 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2997 PLIGHTINFOEL
*lightInfo
= NULL
;
2998 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3000 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3001 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3003 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3004 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3005 if(lightInfo
->OriginalIndex
== Index
) break;
3009 if (lightInfo
== NULL
) {
3010 TRACE("Light enabled state requested but light not defined\n");
3011 return WINED3DERR_INVALIDCALL
;
3013 /* true is 128 according to SetLightEnable */
3014 *pEnable
= lightInfo
->enabled
? 128 : 0;
3019 * Get / Set Clip Planes
3021 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3022 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3023 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3025 /* Validate Index */
3026 if (Index
>= GL_LIMITS(clipplanes
)) {
3027 TRACE("Application has requested clipplane this device doesn't support\n");
3028 return WINED3DERR_INVALIDCALL
;
3031 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
3033 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3034 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3035 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3036 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3037 TRACE("Application is setting old values over, nothing to do\n");
3041 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3042 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3043 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3044 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3046 /* Handle recording of state blocks */
3047 if (This
->isRecordingState
) {
3048 TRACE("Recording... not performing anything\n");
3052 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3057 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3058 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3059 TRACE("(%p) : for idx %d\n", This
, Index
);
3061 /* Validate Index */
3062 if (Index
>= GL_LIMITS(clipplanes
)) {
3063 TRACE("Application has requested clipplane this device doesn't support\n");
3064 return WINED3DERR_INVALIDCALL
;
3067 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3068 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3069 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3070 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3075 * Get / Set Clip Plane Status
3076 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3078 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3079 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3080 FIXME("(%p) : stub\n", This
);
3081 if (NULL
== pClipStatus
) {
3082 return WINED3DERR_INVALIDCALL
;
3084 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3085 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3089 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3090 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3091 FIXME("(%p) : stub\n", This
);
3092 if (NULL
== pClipStatus
) {
3093 return WINED3DERR_INVALIDCALL
;
3095 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3096 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3101 * Get / Set Material
3103 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3104 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3106 if (!pMaterial
) return WINED3DERR_INVALIDCALL
;
3108 This
->updateStateBlock
->changed
.material
= TRUE
;
3109 This
->updateStateBlock
->material
= *pMaterial
;
3111 /* Handle recording of state blocks */
3112 if (This
->isRecordingState
) {
3113 TRACE("Recording... not performing anything\n");
3117 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3121 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3122 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3123 *pMaterial
= This
->updateStateBlock
->material
;
3124 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3125 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3126 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3127 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3128 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3129 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3130 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3131 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3132 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3140 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3141 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3142 IWineD3DIndexBuffer
*oldIdxs
;
3144 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3145 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3147 This
->updateStateBlock
->changed
.indices
= TRUE
;
3148 This
->updateStateBlock
->pIndexData
= pIndexData
;
3150 /* Handle recording of state blocks */
3151 if (This
->isRecordingState
) {
3152 TRACE("Recording... not performing anything\n");
3153 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3154 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3158 if(oldIdxs
!= pIndexData
) {
3159 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3160 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3161 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3166 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3167 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3169 *ppIndexData
= This
->stateBlock
->pIndexData
;
3171 /* up ref count on ppindexdata */
3173 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3174 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3176 TRACE("(%p) No index data set\n", This
);
3178 TRACE("Returning %p\n", *ppIndexData
);
3183 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3184 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3185 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3186 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3188 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3189 TRACE("Application is setting the old value over, nothing to do\n");
3193 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3195 if (This
->isRecordingState
) {
3196 TRACE("Recording... not performing anything\n");
3199 /* The base vertex index affects the stream sources */
3200 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3204 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3205 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3206 TRACE("(%p) : base_index %p\n", This
, base_index
);
3208 *base_index
= This
->stateBlock
->baseVertexIndex
;
3210 TRACE("Returning %u\n", *base_index
);
3216 * Get / Set Viewports
3218 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3219 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3221 TRACE("(%p)\n", This
);
3222 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3223 This
->updateStateBlock
->viewport
= *pViewport
;
3225 /* Handle recording of state blocks */
3226 if (This
->isRecordingState
) {
3227 TRACE("Recording... not performing anything\n");
3231 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3232 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3234 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3239 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3240 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3241 TRACE("(%p)\n", This
);
3242 *pViewport
= This
->stateBlock
->viewport
;
3247 * Get / Set Render States
3248 * TODO: Verify against dx9 definitions
3250 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3252 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3253 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3255 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3257 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3258 This
->updateStateBlock
->renderState
[State
] = Value
;
3260 /* Handle recording of state blocks */
3261 if (This
->isRecordingState
) {
3262 TRACE("Recording... not performing anything\n");
3266 /* Compared here and not before the assignment to allow proper stateblock recording */
3267 if(Value
== oldValue
) {
3268 TRACE("Application is setting the old value over, nothing to do\n");
3270 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3276 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3277 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3278 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3279 *pValue
= This
->stateBlock
->renderState
[State
];
3284 * Get / Set Sampler States
3285 * TODO: Verify against dx9 definitions
3288 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3289 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3292 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3293 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3295 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3296 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3299 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3300 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3301 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3304 * SetSampler is designed to allow for more than the standard up to 8 textures
3305 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3306 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3308 * http://developer.nvidia.com/object/General_FAQ.html#t6
3310 * There are two new settings for GForce
3312 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3313 * and the texture one:
3314 * GL_MAX_TEXTURE_COORDS_ARB.
3315 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3318 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3319 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3320 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3322 /* Handle recording of state blocks */
3323 if (This
->isRecordingState
) {
3324 TRACE("Recording... not performing anything\n");
3328 if(oldValue
== Value
) {
3329 TRACE("Application is setting the old value over, nothing to do\n");
3333 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3338 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3339 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3341 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3342 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3344 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3345 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3348 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3349 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3350 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3352 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3353 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3358 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3361 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3362 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3363 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3366 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3368 if(This
->isRecordingState
) {
3369 TRACE("Recording... not performing anything\n");
3373 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3378 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3379 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3381 *pRect
= This
->updateStateBlock
->scissorRect
;
3382 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3386 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3387 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3388 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3390 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3392 This
->updateStateBlock
->vertexDecl
= pDecl
;
3393 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3395 if (This
->isRecordingState
) {
3396 TRACE("Recording... not performing anything\n");
3398 } else if(pDecl
== oldDecl
) {
3399 /* Checked after the assignment to allow proper stateblock recording */
3400 TRACE("Application is setting the old declaration over, nothing to do\n");
3404 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3408 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3409 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3411 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3413 *ppDecl
= This
->stateBlock
->vertexDecl
;
3414 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3418 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3419 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3420 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3422 This
->updateStateBlock
->vertexShader
= pShader
;
3423 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3425 if (This
->isRecordingState
) {
3426 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3427 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3428 TRACE("Recording... not performing anything\n");
3430 } else if(oldShader
== pShader
) {
3431 /* Checked here to allow proper stateblock recording */
3432 TRACE("App is setting the old shader over, nothing to do\n");
3436 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3437 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3438 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3440 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3445 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3446 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3448 if (NULL
== ppShader
) {
3449 return WINED3DERR_INVALIDCALL
;
3451 *ppShader
= This
->stateBlock
->vertexShader
;
3452 if( NULL
!= *ppShader
)
3453 IWineD3DVertexShader_AddRef(*ppShader
);
3455 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3459 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3460 IWineD3DDevice
*iface
,
3462 CONST BOOL
*srcData
,
3465 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3466 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3468 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3469 iface
, srcData
, start
, count
);
3471 if (srcData
== NULL
|| cnt
< 0)
3472 return WINED3DERR_INVALIDCALL
;
3474 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3475 for (i
= 0; i
< cnt
; i
++)
3476 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3478 for (i
= start
; i
< cnt
+ start
; ++i
) {
3479 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3482 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3487 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3488 IWineD3DDevice
*iface
,
3493 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3494 int cnt
= min(count
, MAX_CONST_B
- start
);
3496 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3497 iface
, dstData
, start
, count
);
3499 if (dstData
== NULL
|| cnt
< 0)
3500 return WINED3DERR_INVALIDCALL
;
3502 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3506 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3507 IWineD3DDevice
*iface
,
3512 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3513 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3515 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3516 iface
, srcData
, start
, count
);
3518 if (srcData
== NULL
|| cnt
< 0)
3519 return WINED3DERR_INVALIDCALL
;
3521 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3522 for (i
= 0; i
< cnt
; i
++)
3523 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3524 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3526 for (i
= start
; i
< cnt
+ start
; ++i
) {
3527 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3530 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3535 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3536 IWineD3DDevice
*iface
,
3541 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3542 int cnt
= min(count
, MAX_CONST_I
- start
);
3544 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3545 iface
, dstData
, start
, count
);
3547 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3548 return WINED3DERR_INVALIDCALL
;
3550 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3554 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3555 IWineD3DDevice
*iface
,
3557 CONST
float *srcData
,
3560 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3563 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3564 iface
, srcData
, start
, count
);
3566 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3567 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3568 return WINED3DERR_INVALIDCALL
;
3570 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3572 for (i
= 0; i
< count
; i
++)
3573 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3574 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3577 for (i
= start
; i
< count
+ start
; ++i
) {
3578 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3579 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3580 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3581 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3582 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3584 ptr
->idx
[ptr
->count
++] = i
;
3585 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3589 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3594 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3595 IWineD3DDevice
*iface
,
3597 CONST
float *srcData
,
3600 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3603 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3604 iface
, srcData
, start
, count
);
3606 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3607 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3608 return WINED3DERR_INVALIDCALL
;
3610 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3612 for (i
= 0; i
< count
; i
++)
3613 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3614 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3617 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3618 * context. On a context switch the old context will be fully dirtified
3620 memset(This
->activeContext
->vshader_const_dirty
+ start
, 1,
3621 sizeof(*This
->activeContext
->vshader_const_dirty
) * count
);
3622 This
->highest_dirty_vs_const
= max(This
->highest_dirty_vs_const
, start
+count
+1);
3624 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3629 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3630 IWineD3DDevice
*iface
,
3635 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3636 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3638 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3639 iface
, dstData
, start
, count
);
3641 if (dstData
== NULL
|| cnt
< 0)
3642 return WINED3DERR_INVALIDCALL
;
3644 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3648 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3650 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3651 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3655 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3656 int i
= This
->rev_tex_unit_map
[unit
];
3657 int j
= This
->texUnitMap
[stage
];
3659 This
->texUnitMap
[stage
] = unit
;
3660 if (i
!= -1 && i
!= stage
) {
3661 This
->texUnitMap
[i
] = -1;
3664 This
->rev_tex_unit_map
[unit
] = stage
;
3665 if (j
!= -1 && j
!= unit
) {
3666 This
->rev_tex_unit_map
[j
] = -1;
3670 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3673 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3674 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3675 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3676 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3677 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3678 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3679 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3680 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3681 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3683 if (color_op
== WINED3DTOP_DISABLE
) {
3684 /* Not used, and disable higher stages */
3685 while (i
< MAX_TEXTURES
) {
3686 This
->fixed_function_usage_map
[i
] = FALSE
;
3692 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3693 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3694 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3695 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3696 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3697 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3698 This
->fixed_function_usage_map
[i
] = TRUE
;
3700 This
->fixed_function_usage_map
[i
] = FALSE
;
3703 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3704 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3709 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3712 device_update_fixed_function_usage_map(This
);
3714 if (!GL_SUPPORT(NV_REGISTER_COMBINERS
) || This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3715 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3716 if (!This
->fixed_function_usage_map
[i
]) continue;
3718 if (This
->texUnitMap
[i
] != i
) {
3719 device_map_stage(This
, i
, i
);
3720 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3721 markTextureStagesDirty(This
, i
);
3727 /* Now work out the mapping */
3729 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3730 if (!This
->fixed_function_usage_map
[i
]) continue;
3732 if (This
->texUnitMap
[i
] != tex
) {
3733 device_map_stage(This
, i
, tex
);
3734 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3735 markTextureStagesDirty(This
, i
);
3742 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3743 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3746 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3747 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3748 device_map_stage(This
, i
, i
);
3749 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3750 if (i
< MAX_TEXTURES
) {
3751 markTextureStagesDirty(This
, i
);
3757 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3758 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3760 if (current_mapping
== -1) {
3761 /* Not currently used */
3765 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3766 /* Used by a fragment sampler */
3768 if (!pshader_sampler_tokens
) {
3769 /* No pixel shader, check fixed function */
3770 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3773 /* Pixel shader, check the shader's sampler map */
3774 return !pshader_sampler_tokens
[current_mapping
];
3777 /* Used by a vertex sampler */
3778 return !vshader_sampler_tokens
[current_mapping
];
3781 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3782 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3783 DWORD
*pshader_sampler_tokens
= NULL
;
3784 int start
= GL_LIMITS(combined_samplers
) - 1;
3788 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3790 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3791 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3792 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3795 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3796 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3797 if (vshader_sampler_tokens
[i
]) {
3798 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3799 /* Already mapped somewhere */
3803 while (start
>= 0) {
3804 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3805 device_map_stage(This
, vsampler_idx
, start
);
3806 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3818 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3819 BOOL vs
= use_vs(This
);
3820 BOOL ps
= use_ps(This
);
3823 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3824 * that would be really messy and require shader recompilation
3825 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3826 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3829 device_map_psamplers(This
);
3831 device_map_fixed_function_samplers(This
);
3835 device_map_vsamplers(This
, ps
);
3839 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3840 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3841 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3842 This
->updateStateBlock
->pixelShader
= pShader
;
3843 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3845 /* Handle recording of state blocks */
3846 if (This
->isRecordingState
) {
3847 TRACE("Recording... not performing anything\n");
3850 if (This
->isRecordingState
) {
3851 TRACE("Recording... not performing anything\n");
3852 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3853 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3857 if(pShader
== oldShader
) {
3858 TRACE("App is setting the old pixel shader over, nothing to do\n");
3862 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3863 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3865 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3866 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3871 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3872 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3874 if (NULL
== ppShader
) {
3875 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3876 return WINED3DERR_INVALIDCALL
;
3879 *ppShader
= This
->stateBlock
->pixelShader
;
3880 if (NULL
!= *ppShader
) {
3881 IWineD3DPixelShader_AddRef(*ppShader
);
3883 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3887 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3888 IWineD3DDevice
*iface
,
3890 CONST BOOL
*srcData
,
3893 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3894 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3896 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3897 iface
, srcData
, start
, count
);
3899 if (srcData
== NULL
|| cnt
< 0)
3900 return WINED3DERR_INVALIDCALL
;
3902 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3903 for (i
= 0; i
< cnt
; i
++)
3904 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3906 for (i
= start
; i
< cnt
+ start
; ++i
) {
3907 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3910 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3915 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3916 IWineD3DDevice
*iface
,
3921 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3922 int cnt
= min(count
, MAX_CONST_B
- start
);
3924 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3925 iface
, dstData
, start
, count
);
3927 if (dstData
== NULL
|| cnt
< 0)
3928 return WINED3DERR_INVALIDCALL
;
3930 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3934 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3935 IWineD3DDevice
*iface
,
3940 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3941 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3943 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3944 iface
, srcData
, start
, count
);
3946 if (srcData
== NULL
|| cnt
< 0)
3947 return WINED3DERR_INVALIDCALL
;
3949 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3950 for (i
= 0; i
< cnt
; i
++)
3951 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3952 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3954 for (i
= start
; i
< cnt
+ start
; ++i
) {
3955 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3958 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3963 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3964 IWineD3DDevice
*iface
,
3969 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3970 int cnt
= min(count
, MAX_CONST_I
- start
);
3972 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3973 iface
, dstData
, start
, count
);
3975 if (dstData
== NULL
|| cnt
< 0)
3976 return WINED3DERR_INVALIDCALL
;
3978 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3982 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3983 IWineD3DDevice
*iface
,
3985 CONST
float *srcData
,
3988 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3991 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3992 iface
, srcData
, start
, count
);
3994 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3995 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3996 return WINED3DERR_INVALIDCALL
;
3998 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4000 for (i
= 0; i
< count
; i
++)
4001 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4002 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4005 for (i
= start
; i
< count
+ start
; ++i
) {
4006 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
4007 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
4008 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
4009 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
4010 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
4012 ptr
->idx
[ptr
->count
++] = i
;
4013 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
4017 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4022 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4023 IWineD3DDevice
*iface
,
4025 CONST
float *srcData
,
4028 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4031 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4032 iface
, srcData
, start
, count
);
4034 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4035 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
4036 return WINED3DERR_INVALIDCALL
;
4038 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4040 for (i
= 0; i
< count
; i
++)
4041 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4042 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4045 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4046 * context. On a context switch the old context will be fully dirtified
4048 memset(This
->activeContext
->pshader_const_dirty
+ start
, 1,
4049 sizeof(*This
->activeContext
->pshader_const_dirty
) * count
);
4050 This
->highest_dirty_ps_const
= max(This
->highest_dirty_ps_const
, start
+count
+1);
4052 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4057 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
4058 IWineD3DDevice
*iface
,
4063 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4064 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
4066 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4067 iface
, dstData
, start
, count
);
4069 if (dstData
== NULL
|| cnt
< 0)
4070 return WINED3DERR_INVALIDCALL
;
4072 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4076 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4078 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
4079 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4081 DWORD DestFVF
= dest
->fvf
;
4083 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4087 if (lpStrideData
->u
.s
.normal
.lpData
) {
4088 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4091 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
4092 ERR("Source has no position mask\n");
4093 return WINED3DERR_INVALIDCALL
;
4096 /* We might access VBOs from this code, so hold the lock */
4099 if (dest
->resource
.allocatedMemory
== NULL
) {
4100 /* This may happen if we do direct locking into a vbo. Unlikely,
4101 * but theoretically possible(ddraw processvertices test)
4103 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4104 if(!dest
->resource
.allocatedMemory
) {
4106 ERR("Out of memory\n");
4107 return E_OUTOFMEMORY
;
4111 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4112 checkGLcall("glBindBufferARB");
4113 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4115 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4117 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4118 checkGLcall("glUnmapBufferARB");
4122 /* Get a pointer into the destination vbo(create one if none exists) and
4123 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4125 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
4126 dest
->Flags
|= VBFLAG_CREATEVBO
;
4127 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer
*) dest
);
4131 unsigned char extrabytes
= 0;
4132 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4133 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4134 * this may write 4 extra bytes beyond the area that should be written
4136 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4137 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4138 if(!dest_conv_addr
) {
4139 ERR("Out of memory\n");
4140 /* Continue without storing converted vertices */
4142 dest_conv
= dest_conv_addr
;
4146 * a) WINED3DRS_CLIPPING is enabled
4147 * b) WINED3DVOP_CLIP is passed
4149 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4150 static BOOL warned
= FALSE
;
4152 * The clipping code is not quite correct. Some things need
4153 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4154 * so disable clipping for now.
4155 * (The graphics in Half-Life are broken, and my processvertices
4156 * test crashes with IDirect3DDevice3)
4162 FIXME("Clipping is broken and disabled for now\n");
4164 } else doClip
= FALSE
;
4165 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4167 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4170 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4171 WINED3DTS_PROJECTION
,
4173 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4174 WINED3DTS_WORLDMATRIX(0),
4177 TRACE("View mat:\n");
4178 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
);
4179 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
);
4180 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
);
4181 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
);
4183 TRACE("Proj mat:\n");
4184 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
);
4185 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
);
4186 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
);
4187 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
);
4189 TRACE("World mat:\n");
4190 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
);
4191 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
);
4192 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
);
4193 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
);
4195 /* Get the viewport */
4196 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4197 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4198 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4200 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4201 multiply_matrix(&mat
,&proj_mat
,&mat
);
4203 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4205 for (i
= 0; i
< dwCount
; i
+= 1) {
4206 unsigned int tex_index
;
4208 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4209 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4210 /* The position first */
4212 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4214 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4216 /* Multiplication with world, view and projection matrix */
4217 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
);
4218 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
);
4219 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
);
4220 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
);
4222 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4224 /* WARNING: The following things are taken from d3d7 and were not yet checked
4225 * against d3d8 or d3d9!
4228 /* Clipping conditions: From msdn
4230 * A vertex is clipped if it does not match the following requirements
4234 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4236 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4237 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4242 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4243 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4246 /* "Normal" viewport transformation (not clipped)
4247 * 1) The values are divided by rhw
4248 * 2) The y axis is negative, so multiply it with -1
4249 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4250 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4251 * 4) Multiply x with Width/2 and add Width/2
4252 * 5) The same for the height
4253 * 6) Add the viewpoint X and Y to the 2D coordinates and
4254 * The minimum Z value to z
4255 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4257 * Well, basically it's simply a linear transformation into viewport
4269 z
*= vp
.MaxZ
- vp
.MinZ
;
4271 x
+= vp
.Width
/ 2 + vp
.X
;
4272 y
+= vp
.Height
/ 2 + vp
.Y
;
4277 /* That vertex got clipped
4278 * Contrary to OpenGL it is not dropped completely, it just
4279 * undergoes a different calculation.
4281 TRACE("Vertex got clipped\n");
4288 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4289 * outside of the main vertex buffer memory. That needs some more
4294 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4297 ( (float *) dest_ptr
)[0] = x
;
4298 ( (float *) dest_ptr
)[1] = y
;
4299 ( (float *) dest_ptr
)[2] = z
;
4300 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4302 dest_ptr
+= 3 * sizeof(float);
4304 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4305 dest_ptr
+= sizeof(float);
4310 ( (float *) dest_conv
)[0] = x
* w
;
4311 ( (float *) dest_conv
)[1] = y
* w
;
4312 ( (float *) dest_conv
)[2] = z
* w
;
4313 ( (float *) dest_conv
)[3] = w
;
4315 dest_conv
+= 3 * sizeof(float);
4317 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4318 dest_conv
+= sizeof(float);
4322 if (DestFVF
& WINED3DFVF_PSIZE
) {
4323 dest_ptr
+= sizeof(DWORD
);
4324 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4326 if (DestFVF
& WINED3DFVF_NORMAL
) {
4328 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4329 /* AFAIK this should go into the lighting information */
4330 FIXME("Didn't expect the destination to have a normal\n");
4331 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4333 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4337 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4339 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4341 static BOOL warned
= FALSE
;
4344 ERR("No diffuse color in source, but destination has one\n");
4348 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4349 dest_ptr
+= sizeof(DWORD
);
4352 *( (DWORD
*) dest_conv
) = 0xffffffff;
4353 dest_conv
+= sizeof(DWORD
);
4357 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4359 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4360 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4361 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4362 dest_conv
+= sizeof(DWORD
);
4367 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4368 /* What's the color value in the feedback buffer? */
4370 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4372 static BOOL warned
= FALSE
;
4375 ERR("No specular color in source, but destination has one\n");
4379 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4380 dest_ptr
+= sizeof(DWORD
);
4383 *( (DWORD
*) dest_conv
) = 0xFF000000;
4384 dest_conv
+= sizeof(DWORD
);
4388 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4390 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4391 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4392 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4393 dest_conv
+= sizeof(DWORD
);
4398 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4400 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4401 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4403 ERR("No source texture, but destination requests one\n");
4404 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4405 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4408 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4410 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4417 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4418 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4419 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4420 dwCount
* get_flexible_vertex_size(DestFVF
),
4422 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4423 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4430 #undef copy_and_next
4432 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4433 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4434 WineDirect3DVertexStridedData strided
;
4435 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4436 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4439 ERR("Output vertex declaration not implemented yet\n");
4442 /* Need any context to write to the vbo. */
4443 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4445 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4446 * control the streamIsUP flag, thus restore it afterwards.
4448 This
->stateBlock
->streamIsUP
= FALSE
;
4449 memset(&strided
, 0, sizeof(strided
));
4450 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4451 This
->stateBlock
->streamIsUP
= streamWasUP
;
4453 if(vbo
|| SrcStartIndex
) {
4455 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4456 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4458 * Also get the start index in, but only loop over all elements if there's something to add at all.
4460 #define FIXSRC(type) \
4461 if(strided.u.s.type.VBO) { \
4462 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4463 strided.u.s.type.VBO = 0; \
4464 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4466 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4470 if(strided.u.s.type.lpData) { \
4471 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4474 FIXSRC(blendWeights
);
4475 FIXSRC(blendMatrixIndices
);
4480 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4481 FIXSRC(texCoords
[i
]);
4494 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4498 * Get / Set Texture Stage States
4499 * TODO: Verify against dx9 definitions
4501 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4502 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4503 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4505 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4507 if (Stage
>= MAX_TEXTURES
) {
4508 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4512 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4513 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4515 if (This
->isRecordingState
) {
4516 TRACE("Recording... not performing anything\n");
4520 /* Checked after the assignments to allow proper stateblock recording */
4521 if(oldValue
== Value
) {
4522 TRACE("App is setting the old value over, nothing to do\n");
4526 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4527 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4528 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4529 * Changes in other states are important on disabled stages too
4534 if(Type
== WINED3DTSS_COLOROP
) {
4537 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4538 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4539 * they have to be disabled
4541 * The current stage is dirtified below.
4543 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4544 TRACE("Additionally dirtifying stage %d\n", i
);
4545 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4547 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4548 TRACE("New lowest disabled: %d\n", Stage
);
4549 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4550 /* Previously disabled stage enabled. Stages above it may need enabling
4551 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4552 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4554 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4557 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4558 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4561 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4562 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4564 This
->stateBlock
->lowest_disabled_stage
= i
;
4565 TRACE("New lowest disabled: %d\n", i
);
4567 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4568 /* TODO: Built a stage -> texture unit mapping for register combiners */
4572 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4577 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4579 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4580 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4587 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4588 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4589 IWineD3DBaseTexture
*oldTexture
;
4591 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4593 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4594 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4597 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4598 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4599 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4602 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4604 if(pTexture
!= NULL
) {
4605 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4607 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4608 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4609 return WINED3DERR_INVALIDCALL
;
4611 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4614 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4615 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4617 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4618 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4619 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4621 /* Handle recording of state blocks */
4622 if (This
->isRecordingState
) {
4623 TRACE("Recording... not performing anything\n");
4627 if(oldTexture
== pTexture
) {
4628 TRACE("App is setting the same texture again, nothing to do\n");
4632 /** NOTE: MSDN says that setTexture increases the reference count,
4633 * and that the application must set the texture back to null (or have a leaky application),
4634 * This means we should pass the refcount up to the parent
4635 *******************************/
4636 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4637 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4638 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4640 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4641 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4642 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4643 * so the COLOROP and ALPHAOP have to be dirtified.
4645 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4646 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4648 if(bindCount
== 1) {
4649 new->baseTexture
.sampler
= Stage
;
4651 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4655 if (NULL
!= oldTexture
) {
4656 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4657 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4659 IWineD3DBaseTexture_Release(oldTexture
);
4660 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4661 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4662 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4665 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4667 /* Have to do a search for the other sampler(s) where the texture is bound to
4668 * Shouldn't happen as long as apps bind a texture only to one stage
4670 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4671 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4672 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4673 old
->baseTexture
.sampler
= i
;
4680 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4685 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4686 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4688 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4690 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4691 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4694 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4695 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4696 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4699 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4701 IWineD3DBaseTexture_AddRef(*ppTexture
);
4703 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4711 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4712 IWineD3DSurface
**ppBackBuffer
) {
4713 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4714 IWineD3DSwapChain
*swapChain
;
4717 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4719 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4720 if (hr
== WINED3D_OK
) {
4721 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4722 IWineD3DSwapChain_Release(swapChain
);
4724 *ppBackBuffer
= NULL
;
4729 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4730 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4731 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4732 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4735 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4736 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4737 IWineD3DSwapChain
*swapChain
;
4740 if(iSwapChain
> 0) {
4741 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4742 if (hr
== WINED3D_OK
) {
4743 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4744 IWineD3DSwapChain_Release(swapChain
);
4746 FIXME("(%p) Error getting display mode\n", This
);
4749 /* Don't read the real display mode,
4750 but return the stored mode instead. X11 can't change the color
4751 depth, and some apps are pretty angry if they SetDisplayMode from
4752 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4754 Also don't relay to the swapchain because with ddraw it's possible
4755 that there isn't a swapchain at all */
4756 pMode
->Width
= This
->ddraw_width
;
4757 pMode
->Height
= This
->ddraw_height
;
4758 pMode
->Format
= This
->ddraw_format
;
4759 pMode
->RefreshRate
= 0;
4766 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4767 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4768 TRACE("(%p)->(%p)\n", This
, hWnd
);
4770 if(This
->ddraw_fullscreen
) {
4771 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4772 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4774 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4775 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4779 This
->ddraw_window
= hWnd
;
4783 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4784 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4785 TRACE("(%p)->(%p)\n", This
, hWnd
);
4787 *hWnd
= This
->ddraw_window
;
4792 * Stateblock related functions
4795 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4796 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4797 IWineD3DStateBlockImpl
*object
;
4798 HRESULT temp_result
;
4801 TRACE("(%p)\n", This
);
4803 if (This
->isRecordingState
) {
4804 return WINED3DERR_INVALIDCALL
;
4807 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4808 if (NULL
== object
) {
4809 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4810 return E_OUTOFMEMORY
;
4812 TRACE("(%p) created object %p\n", This
, object
);
4813 object
->wineD3DDevice
= This
;
4814 /** FIXME: object->parent = parent; **/
4815 object
->parent
= NULL
;
4816 object
->blockType
= WINED3DSBT_RECORDED
;
4818 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4820 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4821 list_init(&object
->lightMap
[i
]);
4824 temp_result
= allocate_shader_constants(object
);
4825 if (WINED3D_OK
!= temp_result
)
4828 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4829 This
->updateStateBlock
= object
;
4830 This
->isRecordingState
= TRUE
;
4832 TRACE("(%p) recording stateblock %p\n",This
, object
);
4836 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4837 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4839 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4841 if (!This
->isRecordingState
) {
4842 FIXME("(%p) not recording! returning error\n", This
);
4843 *ppStateBlock
= NULL
;
4844 return WINED3DERR_INVALIDCALL
;
4847 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4848 if(object
->changed
.renderState
[i
]) {
4849 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4850 object
->num_contained_render_states
++;
4853 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4854 if(object
->changed
.transform
[i
]) {
4855 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4856 object
->num_contained_transform_states
++;
4859 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4860 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4861 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4862 object
->num_contained_vs_consts_f
++;
4865 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4866 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4867 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4868 object
->num_contained_vs_consts_i
++;
4871 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4872 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4873 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4874 object
->num_contained_vs_consts_b
++;
4877 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4878 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4879 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4880 object
->num_contained_ps_consts_i
++;
4883 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4884 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4885 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4886 object
->num_contained_ps_consts_b
++;
4889 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4890 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4891 if(object
->changed
.textureState
[i
][j
]) {
4892 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4893 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4894 object
->num_contained_tss_states
++;
4898 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4899 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4900 if(object
->changed
.samplerState
[i
][j
]) {
4901 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4902 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4903 object
->num_contained_sampler_states
++;
4908 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4909 This
->isRecordingState
= FALSE
;
4910 This
->updateStateBlock
= This
->stateBlock
;
4911 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4912 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4913 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4918 * Scene related functions
4920 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4921 /* At the moment we have no need for any functionality at the beginning
4923 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4924 TRACE("(%p)\n", This
);
4927 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4928 return WINED3DERR_INVALIDCALL
;
4930 This
->inScene
= TRUE
;
4934 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4935 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4936 TRACE("(%p)\n", This
);
4938 if(!This
->inScene
) {
4939 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4940 return WINED3DERR_INVALIDCALL
;
4943 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4944 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4947 checkGLcall("glFlush");
4950 This
->inScene
= FALSE
;
4954 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4955 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4956 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4957 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4958 IWineD3DSwapChain
*swapChain
= NULL
;
4960 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4962 TRACE("(%p) Presenting the frame\n", This
);
4964 for(i
= 0 ; i
< swapchains
; i
++) {
4966 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4967 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4968 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4969 IWineD3DSwapChain_Release(swapChain
);
4975 /* Not called from the VTable (internal subroutine) */
4976 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4977 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4978 float Z
, DWORD Stencil
) {
4979 GLbitfield glMask
= 0;
4981 WINED3DRECT curRect
;
4983 WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4984 UINT drawable_width
, drawable_height
;
4985 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4987 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4988 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4989 * for the cleared parts, and the untouched parts.
4991 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4992 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4993 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4994 * checking all this if the dest surface is in the drawable anyway.
4996 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4998 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4999 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
5000 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5003 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5004 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5005 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
5006 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
5007 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5010 if(Count
> 0 && pRects
&& (
5011 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5012 pRects
[0].x2
< target
->currentDesc
.Width
||
5013 pRects
[0].y2
< target
->currentDesc
.Height
)) {
5014 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5021 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
5023 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
5026 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5027 apply_fbo_state((IWineD3DDevice
*) This
);
5030 /* Only set the values up once, as they are not changing */
5031 if (Flags
& WINED3DCLEAR_STENCIL
) {
5032 glClearStencil(Stencil
);
5033 checkGLcall("glClearStencil");
5034 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
5035 glStencilMask(0xFFFFFFFF);
5038 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5039 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5040 glDepthMask(GL_TRUE
);
5042 checkGLcall("glClearDepth");
5043 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
5044 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
5046 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
5047 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
5048 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5050 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5051 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5052 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
5053 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
5054 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5056 else if (Count
> 0 && pRects
&& (
5057 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5058 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
5059 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
5060 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5064 if (Flags
& WINED3DCLEAR_TARGET
) {
5065 TRACE("Clearing screen with glClear to color %x\n", Color
);
5066 glClearColor(D3DCOLOR_R(Color
),
5070 checkGLcall("glClearColor");
5072 /* Clear ALL colors! */
5073 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5074 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
5077 vp_rect
.left
= vp
->X
;
5078 vp_rect
.top
= vp
->Y
;
5079 vp_rect
.right
= vp
->X
+ vp
->Width
;
5080 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5081 if (!(Count
> 0 && pRects
)) {
5082 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5083 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5085 if(This
->render_offscreen
) {
5086 glScissor(vp_rect
.left
, vp_rect
.top
,
5087 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5089 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5090 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5092 checkGLcall("glScissor");
5094 checkGLcall("glClear");
5096 /* Now process each rect in turn */
5097 for (i
= 0; i
< Count
; i
++) {
5098 /* Note gl uses lower left, width/height */
5099 IntersectRect((RECT
*) &curRect
, &vp_rect
, (RECT
*) &pRects
[i
]);
5100 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5101 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5103 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5104 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5105 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5106 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5108 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5109 * The rectangle is not cleared, no error is returned, but further rectanlges are
5110 * still cleared if they are valid
5112 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5113 TRACE("Rectangle with negative dimensions, ignoring\n");
5117 if(This
->render_offscreen
) {
5118 glScissor(curRect
.x1
, curRect
.y1
,
5119 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5121 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5122 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5124 checkGLcall("glScissor");
5127 checkGLcall("glClear");
5131 /* Restore the old values (why..?) */
5132 if (Flags
& WINED3DCLEAR_STENCIL
) {
5133 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5135 if (Flags
& WINED3DCLEAR_TARGET
) {
5136 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5137 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5138 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5139 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5140 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5142 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5143 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5145 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5146 /* TODO: Move the fbo logic into ModifyLocation() */
5147 if(This
->render_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5148 target
->Flags
|= SFLAG_INTEXTURE
;
5151 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5152 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5153 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5154 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5162 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5163 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5164 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5165 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5167 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5168 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5170 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5171 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5172 /* TODO: What about depth stencil buffers without stencil bits? */
5173 return WINED3DERR_INVALIDCALL
;
5176 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5182 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
5183 UINT PrimitiveCount
) {
5185 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5187 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
5188 debug_d3dprimitivetype(PrimitiveType
),
5189 StartVertex
, PrimitiveCount
);
5191 if(!This
->stateBlock
->vertexDecl
) {
5192 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5193 return WINED3DERR_INVALIDCALL
;
5196 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5197 if(This
->stateBlock
->streamIsUP
) {
5198 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5199 This
->stateBlock
->streamIsUP
= FALSE
;
5202 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5203 This
->stateBlock
->loadBaseVertexIndex
= 0;
5204 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5206 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5207 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
5208 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5212 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5213 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5214 WINED3DPRIMITIVETYPE PrimitiveType
,
5215 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
5217 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5219 IWineD3DIndexBuffer
*pIB
;
5220 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
5223 pIB
= This
->stateBlock
->pIndexData
;
5225 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5226 * without an index buffer set. (The first time at least...)
5227 * D3D8 simply dies, but I doubt it can do much harm to return
5228 * D3DERR_INVALIDCALL there as well. */
5229 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5230 return WINED3DERR_INVALIDCALL
;
5233 if(!This
->stateBlock
->vertexDecl
) {
5234 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5235 return WINED3DERR_INVALIDCALL
;
5238 if(This
->stateBlock
->streamIsUP
) {
5239 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5240 This
->stateBlock
->streamIsUP
= FALSE
;
5242 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5244 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5245 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5246 minIndex
, NumVertices
, startIndex
, primCount
);
5248 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5249 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5255 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5256 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5257 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5260 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5261 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5266 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5267 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5268 UINT VertexStreamZeroStride
) {
5269 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5270 IWineD3DVertexBuffer
*vb
;
5272 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5273 debug_d3dprimitivetype(PrimitiveType
),
5274 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5276 if(!This
->stateBlock
->vertexDecl
) {
5277 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5278 return WINED3DERR_INVALIDCALL
;
5281 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5282 vb
= This
->stateBlock
->streamSource
[0];
5283 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5284 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5285 This
->stateBlock
->streamOffset
[0] = 0;
5286 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5287 This
->stateBlock
->streamIsUP
= TRUE
;
5288 This
->stateBlock
->loadBaseVertexIndex
= 0;
5290 /* TODO: Only mark dirty if drawing from a different UP address */
5291 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5293 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5294 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5296 /* MSDN specifies stream zero settings must be set to NULL */
5297 This
->stateBlock
->streamStride
[0] = 0;
5298 This
->stateBlock
->streamSource
[0] = NULL
;
5300 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5301 * the new stream sources or use UP drawing again
5306 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5307 UINT MinVertexIndex
, UINT NumVertices
,
5308 UINT PrimitiveCount
, CONST
void* pIndexData
,
5309 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5310 UINT VertexStreamZeroStride
) {
5312 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5313 IWineD3DVertexBuffer
*vb
;
5314 IWineD3DIndexBuffer
*ib
;
5316 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5317 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5318 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5319 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5321 if(!This
->stateBlock
->vertexDecl
) {
5322 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5323 return WINED3DERR_INVALIDCALL
;
5326 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5332 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5333 vb
= This
->stateBlock
->streamSource
[0];
5334 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5335 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5336 This
->stateBlock
->streamIsUP
= TRUE
;
5337 This
->stateBlock
->streamOffset
[0] = 0;
5338 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5340 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5341 This
->stateBlock
->baseVertexIndex
= 0;
5342 This
->stateBlock
->loadBaseVertexIndex
= 0;
5343 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5344 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5345 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5347 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5349 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5350 This
->stateBlock
->streamSource
[0] = NULL
;
5351 This
->stateBlock
->streamStride
[0] = 0;
5352 ib
= This
->stateBlock
->pIndexData
;
5354 IWineD3DIndexBuffer_Release(ib
);
5355 This
->stateBlock
->pIndexData
= NULL
;
5357 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5358 * SetStreamSource to specify a vertex buffer
5364 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5365 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5367 /* Mark the state dirty until we have nicer tracking
5368 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5371 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5372 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5373 This
->stateBlock
->baseVertexIndex
= 0;
5374 This
->up_strided
= DrawPrimStrideData
;
5375 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5376 This
->up_strided
= NULL
;
5380 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5381 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5382 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5384 /* Mark the state dirty until we have nicer tracking
5385 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5388 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5389 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5390 This
->stateBlock
->streamIsUP
= TRUE
;
5391 This
->stateBlock
->baseVertexIndex
= 0;
5392 This
->up_strided
= DrawPrimStrideData
;
5393 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5394 This
->up_strided
= NULL
;
5398 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5399 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5400 * not callable by the app directly no parameter validation checks are needed here.
5402 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5403 WINED3DLOCKED_BOX src
;
5404 WINED3DLOCKED_BOX dst
;
5406 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5408 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5409 * dirtification to improve loading performance.
5411 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5412 if(FAILED(hr
)) return hr
;
5413 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5415 IWineD3DVolume_UnlockBox(pSourceVolume
);
5419 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5421 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5423 IWineD3DVolume_UnlockBox(pSourceVolume
);
5425 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5430 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5431 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5432 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5433 HRESULT hr
= WINED3D_OK
;
5434 WINED3DRESOURCETYPE sourceType
;
5435 WINED3DRESOURCETYPE destinationType
;
5438 /* TODO: think about moving the code into IWineD3DBaseTexture */
5440 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5442 /* verify that the source and destination textures aren't NULL */
5443 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5444 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5445 This
, pSourceTexture
, pDestinationTexture
);
5446 hr
= WINED3DERR_INVALIDCALL
;
5449 if (pSourceTexture
== pDestinationTexture
) {
5450 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5451 This
, pSourceTexture
, pDestinationTexture
);
5452 hr
= WINED3DERR_INVALIDCALL
;
5454 /* Verify that the source and destination textures are the same type */
5455 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5456 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5458 if (sourceType
!= destinationType
) {
5459 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5461 hr
= WINED3DERR_INVALIDCALL
;
5464 /* check that both textures have the identical numbers of levels */
5465 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5466 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5467 hr
= WINED3DERR_INVALIDCALL
;
5470 if (WINED3D_OK
== hr
) {
5472 /* Make sure that the destination texture is loaded */
5473 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5475 /* Update every surface level of the texture */
5476 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5478 switch (sourceType
) {
5479 case WINED3DRTYPE_TEXTURE
:
5481 IWineD3DSurface
*srcSurface
;
5482 IWineD3DSurface
*destSurface
;
5484 for (i
= 0 ; i
< levels
; ++i
) {
5485 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5486 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5487 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5488 IWineD3DSurface_Release(srcSurface
);
5489 IWineD3DSurface_Release(destSurface
);
5490 if (WINED3D_OK
!= hr
) {
5491 WARN("(%p) : Call to update surface failed\n", This
);
5497 case WINED3DRTYPE_CUBETEXTURE
:
5499 IWineD3DSurface
*srcSurface
;
5500 IWineD3DSurface
*destSurface
;
5501 WINED3DCUBEMAP_FACES faceType
;
5503 for (i
= 0 ; i
< levels
; ++i
) {
5504 /* Update each cube face */
5505 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5506 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5507 if (WINED3D_OK
!= hr
) {
5508 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5510 TRACE("Got srcSurface %p\n", srcSurface
);
5512 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5513 if (WINED3D_OK
!= hr
) {
5514 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5516 TRACE("Got desrSurface %p\n", destSurface
);
5518 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5519 IWineD3DSurface_Release(srcSurface
);
5520 IWineD3DSurface_Release(destSurface
);
5521 if (WINED3D_OK
!= hr
) {
5522 WARN("(%p) : Call to update surface failed\n", This
);
5530 case WINED3DRTYPE_VOLUMETEXTURE
:
5532 IWineD3DVolume
*srcVolume
= NULL
;
5533 IWineD3DVolume
*destVolume
= NULL
;
5535 for (i
= 0 ; i
< levels
; ++i
) {
5536 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5537 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5538 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5539 IWineD3DVolume_Release(srcVolume
);
5540 IWineD3DVolume_Release(destVolume
);
5541 if (WINED3D_OK
!= hr
) {
5542 WARN("(%p) : Call to update volume failed\n", This
);
5550 FIXME("(%p) : Unsupported source and destination type\n", This
);
5551 hr
= WINED3DERR_INVALIDCALL
;
5558 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5559 IWineD3DSwapChain
*swapChain
;
5561 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5562 if(hr
== WINED3D_OK
) {
5563 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5564 IWineD3DSwapChain_Release(swapChain
);
5569 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5571 /* return a sensible default */
5573 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5574 FIXME("(%p) : stub\n", This
);
5578 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5582 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5583 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5584 if (texture
&& (texture
->resource
.format
== WINED3DFMT_P8
|| texture
->resource
.format
== WINED3DFMT_A8P8
)) {
5585 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5590 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5591 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5594 PALETTEENTRY
**palettes
;
5596 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5598 if (PaletteNumber
>= MAX_PALETTES
) {
5599 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5600 return WINED3DERR_INVALIDCALL
;
5603 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5604 NewSize
= This
->NumberOfPalettes
;
5607 } while(PaletteNumber
>= NewSize
);
5608 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5610 ERR("Out of memory!\n");
5611 return E_OUTOFMEMORY
;
5613 This
->palettes
= palettes
;
5614 This
->NumberOfPalettes
= NewSize
;
5617 if (!This
->palettes
[PaletteNumber
]) {
5618 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5619 if (!This
->palettes
[PaletteNumber
]) {
5620 ERR("Out of memory!\n");
5621 return E_OUTOFMEMORY
;
5625 for (j
= 0; j
< 256; ++j
) {
5626 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5627 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5628 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5629 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5631 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5632 TRACE("(%p) : returning\n", This
);
5636 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5637 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5639 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5640 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5641 /* What happens in such situation isn't documented; Native seems to silently abort
5642 on such conditions. Return Invalid Call. */
5643 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5644 return WINED3DERR_INVALIDCALL
;
5646 for (j
= 0; j
< 256; ++j
) {
5647 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5648 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5649 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5650 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5652 TRACE("(%p) : returning\n", This
);
5656 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5657 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5658 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5659 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5660 (tested with reference rasterizer). Return Invalid Call. */
5661 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5662 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5663 return WINED3DERR_INVALIDCALL
;
5665 /*TODO: stateblocks */
5666 if (This
->currentPalette
!= PaletteNumber
) {
5667 This
->currentPalette
= PaletteNumber
;
5668 dirtify_p8_texture_samplers(This
);
5670 TRACE("(%p) : returning\n", This
);
5674 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5675 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5676 if (PaletteNumber
== NULL
) {
5677 WARN("(%p) : returning Invalid Call\n", This
);
5678 return WINED3DERR_INVALIDCALL
;
5680 /*TODO: stateblocks */
5681 *PaletteNumber
= This
->currentPalette
;
5682 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5686 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5687 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5688 static BOOL showFixmes
= TRUE
;
5690 FIXME("(%p) : stub\n", This
);
5694 This
->softwareVertexProcessing
= bSoftware
;
5699 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5700 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5701 static BOOL showFixmes
= TRUE
;
5703 FIXME("(%p) : stub\n", This
);
5706 return This
->softwareVertexProcessing
;
5710 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5711 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5712 IWineD3DSwapChain
*swapChain
;
5715 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5717 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5718 if(hr
== WINED3D_OK
){
5719 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5720 IWineD3DSwapChain_Release(swapChain
);
5722 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5728 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5730 static BOOL showfixmes
= TRUE
;
5731 if(nSegments
!= 0.0f
) {
5733 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5740 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5741 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5742 static BOOL showfixmes
= TRUE
;
5744 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5750 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5751 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5752 /** TODO: remove casts to IWineD3DSurfaceImpl
5753 * NOTE: move code to surface to accomplish this
5754 ****************************************/
5755 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5756 int srcWidth
, srcHeight
;
5757 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5758 WINED3DFORMAT destFormat
, srcFormat
;
5760 int srcLeft
, destLeft
, destTop
;
5761 WINED3DPOOL srcPool
, destPool
;
5763 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5764 glDescriptor
*glDescription
= NULL
;
5768 CONVERT_TYPES convert
= NO_CONVERSION
;
5770 WINED3DSURFACE_DESC winedesc
;
5772 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5773 memset(&winedesc
, 0, sizeof(winedesc
));
5774 winedesc
.Width
= &srcSurfaceWidth
;
5775 winedesc
.Height
= &srcSurfaceHeight
;
5776 winedesc
.Pool
= &srcPool
;
5777 winedesc
.Format
= &srcFormat
;
5779 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5781 winedesc
.Width
= &destSurfaceWidth
;
5782 winedesc
.Height
= &destSurfaceHeight
;
5783 winedesc
.Pool
= &destPool
;
5784 winedesc
.Format
= &destFormat
;
5785 winedesc
.Size
= &destSize
;
5787 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5789 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5790 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5791 return WINED3DERR_INVALIDCALL
;
5794 /* This call loads the opengl surface directly, instead of copying the surface to the
5795 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5796 * copy in sysmem and use regular surface loading.
5798 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5799 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5800 if(convert
!= NO_CONVERSION
) {
5801 return IWineD3DSurface_BltFast(pDestinationSurface
,
5802 pDestPoint
? pDestPoint
->x
: 0,
5803 pDestPoint
? pDestPoint
->y
: 0,
5804 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5807 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5808 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5809 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5811 /* Get the update surface description */
5812 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5815 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5819 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5820 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5821 checkGLcall("glActiveTextureARB");
5824 /* Make sure the surface is loaded and up to date */
5825 IWineD3DSurface_PreLoad(pDestinationSurface
);
5827 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5829 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5830 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5831 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5832 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5833 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5834 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5837 /* This function doesn't support compressed textures
5838 the pitch is just bytesPerPixel * width */
5839 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5840 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5841 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5842 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5844 /* TODO DXT formats */
5846 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5847 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5849 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5851 ,glDescription
->level
5856 ,glDescription
->glFormat
5857 ,glDescription
->glType
5858 ,IWineD3DSurface_GetData(pSourceSurface
)
5862 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5864 /* need to lock the surface to get the data */
5865 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5868 /* TODO: Cube and volume support */
5870 /* not a whole row so we have to do it a line at a time */
5873 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5874 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5876 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5878 glTexSubImage2D(glDescription
->target
5879 ,glDescription
->level
5884 ,glDescription
->glFormat
5885 ,glDescription
->glType
5886 ,data
/* could be quicker using */
5891 } else { /* Full width, so just write out the whole texture */
5893 if (WINED3DFMT_DXT1
== destFormat
||
5894 WINED3DFMT_DXT2
== destFormat
||
5895 WINED3DFMT_DXT3
== destFormat
||
5896 WINED3DFMT_DXT4
== destFormat
||
5897 WINED3DFMT_DXT5
== destFormat
) {
5898 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5899 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5900 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5901 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5902 } if (destFormat
!= srcFormat
) {
5903 FIXME("Updating mixed format compressed texture is not curretly support\n");
5905 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5906 glDescription
->level
,
5907 glDescription
->glFormatInternal
,
5912 IWineD3DSurface_GetData(pSourceSurface
));
5915 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5920 glTexSubImage2D(glDescription
->target
5921 ,glDescription
->level
5926 ,glDescription
->glFormat
5927 ,glDescription
->glType
5928 ,IWineD3DSurface_GetData(pSourceSurface
)
5932 checkGLcall("glTexSubImage2D");
5936 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5937 sampler
= This
->rev_tex_unit_map
[0];
5938 if (sampler
!= -1) {
5939 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5945 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5946 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5947 struct WineD3DRectPatch
*patch
;
5951 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5953 if(!(Handle
|| pRectPatchInfo
)) {
5954 /* TODO: Write a test for the return value, thus the FIXME */
5955 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5956 return WINED3DERR_INVALIDCALL
;
5960 i
= PATCHMAP_HASHFUNC(Handle
);
5962 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5963 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5964 if(patch
->Handle
== Handle
) {
5971 TRACE("Patch does not exist. Creating a new one\n");
5972 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5973 patch
->Handle
= Handle
;
5974 list_add_head(&This
->patches
[i
], &patch
->entry
);
5976 TRACE("Found existing patch %p\n", patch
);
5979 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5980 * attributes we have to tesselate, read back, and draw. This needs a patch
5981 * management structure instance. Create one.
5983 * A possible improvement is to check if a vertex shader is used, and if not directly
5986 FIXME("Drawing an uncached patch. This is slow\n");
5987 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5990 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5991 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5992 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5994 TRACE("Tesselation density or patch info changed, retesselating\n");
5996 if(pRectPatchInfo
) {
5997 patch
->RectPatchInfo
= *pRectPatchInfo
;
5999 patch
->numSegs
[0] = pNumSegs
[0];
6000 patch
->numSegs
[1] = pNumSegs
[1];
6001 patch
->numSegs
[2] = pNumSegs
[2];
6002 patch
->numSegs
[3] = pNumSegs
[3];
6004 hr
= tesselate_rectpatch(This
, patch
);
6006 WARN("Patch tesselation failed\n");
6008 /* Do not release the handle to store the params of the patch */
6010 HeapFree(GetProcessHeap(), 0, patch
);
6016 This
->currentPatch
= patch
;
6017 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
6018 This
->currentPatch
= NULL
;
6020 /* Destroy uncached patches */
6022 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6023 HeapFree(GetProcessHeap(), 0, patch
);
6028 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
6029 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6030 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
6031 FIXME("(%p) : Stub\n", This
);
6035 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
6036 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6038 struct WineD3DRectPatch
*patch
;
6040 TRACE("(%p) Handle(%d)\n", This
, Handle
);
6042 i
= PATCHMAP_HASHFUNC(Handle
);
6043 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6044 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6045 if(patch
->Handle
== Handle
) {
6046 TRACE("Deleting patch %p\n", patch
);
6047 list_remove(&patch
->entry
);
6048 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6049 HeapFree(GetProcessHeap(), 0, patch
);
6054 /* TODO: Write a test for the return value */
6055 FIXME("Attempt to destroy nonexistent patch\n");
6056 return WINED3DERR_INVALIDCALL
;
6059 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6061 IWineD3DSwapChain
*swapchain
;
6063 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6064 if (SUCCEEDED(hr
)) {
6065 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6072 void bind_fbo(IWineD3DDevice
*iface
, GLenum target
, GLuint
*fbo
) {
6073 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6076 GL_EXTCALL(glGenFramebuffersEXT(1, fbo
));
6077 checkGLcall("glGenFramebuffersEXT()");
6079 GL_EXTCALL(glBindFramebufferEXT(target
, *fbo
));
6080 checkGLcall("glBindFramebuffer()");
6083 /* TODO: Handle stencil attachments */
6084 void attach_depth_stencil_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, IWineD3DSurface
*depth_stencil
, BOOL use_render_buffer
) {
6085 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
6087 if (use_render_buffer
&& depth_stencil_impl
->current_renderbuffer
) {
6088 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, depth_stencil_impl
->current_renderbuffer
->id
));
6089 checkGLcall("glFramebufferRenderbufferEXT()");
6091 IWineD3DBaseTextureImpl
*texture_impl
;
6092 GLenum texttarget
, target
;
6093 GLint old_binding
= 0;
6095 texttarget
= depth_stencil_impl
->glDescription
.target
;
6096 if(texttarget
== GL_TEXTURE_2D
) {
6097 target
= GL_TEXTURE_2D
;
6098 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
6099 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
6100 target
= GL_TEXTURE_RECTANGLE_ARB
;
6101 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
6103 target
= GL_TEXTURE_CUBE_MAP_ARB
;
6104 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6107 IWineD3DSurface_PreLoad(depth_stencil
);
6109 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6110 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6111 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
6112 glBindTexture(target
, old_binding
);
6114 /* Update base texture states array */
6115 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6116 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6117 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6118 if (texture_impl
->baseTexture
.bindCount
) {
6119 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6122 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6125 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
,
6126 depth_stencil_impl
->glDescription
.textureName
, depth_stencil_impl
->glDescription
.level
));
6127 checkGLcall("glFramebufferTexture2DEXT()");
6131 static void attach_surface_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, DWORD idx
, IWineD3DSurface
*surface
) {
6132 const IWineD3DSurfaceImpl
*surface_impl
= (IWineD3DSurfaceImpl
*)surface
;
6133 IWineD3DBaseTextureImpl
*texture_impl
;
6134 GLenum texttarget
, target
;
6137 texttarget
= surface_impl
->glDescription
.target
;
6138 if(texttarget
== GL_TEXTURE_2D
) {
6139 target
= GL_TEXTURE_2D
;
6140 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
6141 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
6142 target
= GL_TEXTURE_RECTANGLE_ARB
;
6143 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
6145 target
= GL_TEXTURE_CUBE_MAP_ARB
;
6146 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6149 IWineD3DSurface_PreLoad(surface
);
6151 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6152 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6153 glBindTexture(target
, old_binding
);
6155 /* Update base texture states array */
6156 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6157 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6158 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6159 if (texture_impl
->baseTexture
.bindCount
) {
6160 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6163 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6166 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
,
6167 surface_impl
->glDescription
.textureName
, surface_impl
->glDescription
.level
));
6169 checkGLcall("attach_surface_fbo");
6172 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
6173 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6174 IWineD3DSwapChain
*swapchain
;
6176 swapchain
= get_swapchain(surface
);
6180 TRACE("Surface %p is onscreen\n", surface
);
6182 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6183 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6184 glDrawBuffer(buffer
);
6185 checkGLcall("glDrawBuffer()");
6187 TRACE("Surface %p is offscreen\n", surface
);
6188 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6189 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6190 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6191 checkGLcall("glFramebufferRenderbufferEXT");
6195 glEnable(GL_SCISSOR_TEST
);
6197 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6199 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6200 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6202 checkGLcall("glScissor");
6204 glDisable(GL_SCISSOR_TEST
);
6206 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6208 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6209 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6211 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
6212 glClear(GL_COLOR_BUFFER_BIT
);
6213 checkGLcall("glClear");
6215 if (This
->render_offscreen
) {
6216 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6218 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6219 checkGLcall("glBindFramebuffer()");
6222 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6223 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6224 glDrawBuffer(GL_BACK
);
6225 checkGLcall("glDrawBuffer()");
6229 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6230 unsigned int r
, g
, b
, a
;
6233 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6234 destfmt
== WINED3DFMT_R8G8B8
)
6237 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6239 a
= (color
& 0xff000000) >> 24;
6240 r
= (color
& 0x00ff0000) >> 16;
6241 g
= (color
& 0x0000ff00) >> 8;
6242 b
= (color
& 0x000000ff) >> 0;
6246 case WINED3DFMT_R5G6B5
:
6247 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6254 TRACE("Returning %08x\n", ret
);
6257 case WINED3DFMT_X1R5G5B5
:
6258 case WINED3DFMT_A1R5G5B5
:
6267 TRACE("Returning %08x\n", ret
);
6271 TRACE("Returning %08x\n", a
);
6274 case WINED3DFMT_X4R4G4B4
:
6275 case WINED3DFMT_A4R4G4B4
:
6284 TRACE("Returning %08x\n", ret
);
6287 case WINED3DFMT_R3G3B2
:
6294 TRACE("Returning %08x\n", ret
);
6297 case WINED3DFMT_X8B8G8R8
:
6298 case WINED3DFMT_A8B8G8R8
:
6303 TRACE("Returning %08x\n", ret
);
6306 case WINED3DFMT_A2R10G10B10
:
6308 r
= (r
* 1024) / 256;
6309 g
= (g
* 1024) / 256;
6310 b
= (b
* 1024) / 256;
6315 TRACE("Returning %08x\n", ret
);
6318 case WINED3DFMT_A2B10G10R10
:
6320 r
= (r
* 1024) / 256;
6321 g
= (g
* 1024) / 256;
6322 b
= (b
* 1024) / 256;
6327 TRACE("Returning %08x\n", ret
);
6331 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6336 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6337 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6338 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6340 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6342 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6343 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6344 return WINED3DERR_INVALIDCALL
;
6347 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6349 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6353 /* Just forward this to the DirectDraw blitting engine */
6354 memset(&BltFx
, 0, sizeof(BltFx
));
6355 BltFx
.dwSize
= sizeof(BltFx
);
6356 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6357 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6361 /* rendertarget and depth stencil functions */
6362 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6363 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6365 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6366 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6367 return WINED3DERR_INVALIDCALL
;
6370 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6371 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6372 /* Note inc ref on returned surface */
6373 if(*ppRenderTarget
!= NULL
)
6374 IWineD3DSurface_AddRef(*ppRenderTarget
);
6378 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6379 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6380 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6381 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6382 IWineD3DSwapChainImpl
*Swapchain
;
6385 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6387 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6388 if(hr
!= WINED3D_OK
) {
6389 ERR("Can't get the swapchain\n");
6393 /* Make sure to release the swapchain */
6394 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6396 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6397 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6398 return WINED3DERR_INVALIDCALL
;
6400 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6401 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6402 return WINED3DERR_INVALIDCALL
;
6405 if(Swapchain
->frontBuffer
!= Front
) {
6406 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6408 if(Swapchain
->frontBuffer
)
6409 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6410 Swapchain
->frontBuffer
= Front
;
6412 if(Swapchain
->frontBuffer
) {
6413 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6417 if(Back
&& !Swapchain
->backBuffer
) {
6418 /* We need memory for the back buffer array - only one back buffer this way */
6419 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6420 if(!Swapchain
->backBuffer
) {
6421 ERR("Out of memory\n");
6422 return E_OUTOFMEMORY
;
6426 if(Swapchain
->backBuffer
[0] != Back
) {
6427 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6429 /* What to do about the context here in the case of multithreading? Not sure.
6430 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6433 if(!Swapchain
->backBuffer
[0]) {
6434 /* GL was told to draw to the front buffer at creation,
6437 glDrawBuffer(GL_BACK
);
6438 checkGLcall("glDrawBuffer(GL_BACK)");
6439 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6440 Swapchain
->presentParms
.BackBufferCount
= 1;
6442 /* That makes problems - disable for now */
6443 /* glDrawBuffer(GL_FRONT); */
6444 checkGLcall("glDrawBuffer(GL_FRONT)");
6445 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6446 Swapchain
->presentParms
.BackBufferCount
= 0;
6450 if(Swapchain
->backBuffer
[0])
6451 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6452 Swapchain
->backBuffer
[0] = Back
;
6454 if(Swapchain
->backBuffer
[0]) {
6455 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6457 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6458 Swapchain
->backBuffer
= NULL
;
6466 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6467 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6468 *ppZStencilSurface
= This
->stencilBufferTarget
;
6469 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6471 if(*ppZStencilSurface
!= NULL
) {
6472 /* Note inc ref on returned surface */
6473 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6476 return WINED3DERR_NOTFOUND
;
6480 /* TODO: Handle stencil attachments */
6481 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
6482 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6484 TRACE("Set depth stencil to %p\n", depth_stencil
);
6486 if (depth_stencil
) {
6487 attach_depth_stencil_fbo(This
, GL_FRAMEBUFFER_EXT
, depth_stencil
, TRUE
);
6489 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
6490 checkGLcall("glFramebufferTexture2DEXT()");
6494 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
6495 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6497 TRACE("Set render target %u to %p\n", idx
, render_target
);
6499 if (render_target
) {
6500 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, idx
, render_target
);
6501 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
6503 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
6504 checkGLcall("glFramebufferTexture2DEXT()");
6506 This
->draw_buffers
[idx
] = GL_NONE
;
6510 static void check_fbo_status(IWineD3DDevice
*iface
) {
6511 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6514 status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
6515 if (status
== GL_FRAMEBUFFER_COMPLETE_EXT
) {
6516 TRACE("FBO complete\n");
6518 IWineD3DSurfaceImpl
*attachment
;
6520 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status
), status
);
6522 /* Dump the FBO attachments */
6523 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6524 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_color_attachments
[i
];
6526 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i
, attachment
, debug_d3dformat(attachment
->resource
.format
),
6527 attachment
->pow2Width
, attachment
->pow2Height
);
6530 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_depth_attachment
;
6532 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment
, debug_d3dformat(attachment
->resource
.format
),
6533 attachment
->pow2Width
, attachment
->pow2Height
);
6538 static BOOL
depth_mismatch_fbo(IWineD3DDevice
*iface
) {
6539 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6540 IWineD3DSurfaceImpl
*rt_impl
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
6541 IWineD3DSurfaceImpl
*ds_impl
= (IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
;
6543 if (!ds_impl
) return FALSE
;
6545 if (ds_impl
->current_renderbuffer
) {
6546 return (rt_impl
->pow2Width
!= ds_impl
->current_renderbuffer
->width
||
6547 rt_impl
->pow2Height
!= ds_impl
->current_renderbuffer
->height
);
6550 return (rt_impl
->pow2Width
!= ds_impl
->pow2Width
||
6551 rt_impl
->pow2Height
!= ds_impl
->pow2Height
);
6554 void apply_fbo_state(IWineD3DDevice
*iface
) {
6555 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6558 if (This
->render_offscreen
) {
6559 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6561 /* Apply render targets */
6562 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6563 IWineD3DSurface
*render_target
= This
->render_targets
[i
];
6564 if (This
->fbo_color_attachments
[i
] != render_target
) {
6565 set_render_target_fbo(iface
, i
, render_target
);
6566 This
->fbo_color_attachments
[i
] = render_target
;
6570 /* Apply depth targets */
6571 if (This
->fbo_depth_attachment
!= This
->stencilBufferTarget
|| depth_mismatch_fbo(iface
)) {
6572 unsigned int w
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Width
;
6573 unsigned int h
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Height
;
6575 if (This
->stencilBufferTarget
) {
6576 surface_set_compatible_renderbuffer(This
->stencilBufferTarget
, w
, h
);
6578 set_depth_stencil_fbo(iface
, This
->stencilBufferTarget
);
6579 This
->fbo_depth_attachment
= This
->stencilBufferTarget
;
6582 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
6583 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
6584 checkGLcall("glDrawBuffers()");
6586 glDrawBuffer(This
->draw_buffers
[0]);
6587 checkGLcall("glDrawBuffer()");
6590 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6593 check_fbo_status(iface
);
6596 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6597 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6598 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6599 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6600 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6603 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6604 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6605 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6606 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6609 case WINED3DTEXF_LINEAR
:
6610 gl_filter
= GL_LINEAR
;
6614 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6615 case WINED3DTEXF_NONE
:
6616 case WINED3DTEXF_POINT
:
6617 gl_filter
= GL_NEAREST
;
6621 /* Attach src surface to src fbo */
6622 src_swapchain
= get_swapchain(src_surface
);
6623 if (src_swapchain
) {
6626 TRACE("Source surface %p is onscreen\n", src_surface
);
6627 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6628 /* Make sure the drawable is up to date. In the offscreen case
6629 * attach_surface_fbo() implicitly takes care of this. */
6630 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6633 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6634 buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6635 glReadBuffer(buffer
);
6636 checkGLcall("glReadBuffer()");
6638 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6639 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6641 TRACE("Source surface %p is offscreen\n", src_surface
);
6643 bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->src_fbo
);
6644 attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6645 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6646 checkGLcall("glReadBuffer()");
6647 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6648 checkGLcall("glFramebufferRenderbufferEXT");
6652 /* Attach dst surface to dst fbo */
6653 dst_swapchain
= get_swapchain(dst_surface
);
6654 if (dst_swapchain
) {
6657 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6658 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6659 /* Make sure the drawable is up to date. In the offscreen case
6660 * attach_surface_fbo() implicitly takes care of this. */
6661 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6664 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6665 buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6666 glDrawBuffer(buffer
);
6667 checkGLcall("glDrawBuffer()");
6669 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6670 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6672 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6674 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6675 if(!src_swapchain
) {
6676 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6680 bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6681 attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6682 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6683 checkGLcall("glDrawBuffer()");
6684 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6685 checkGLcall("glFramebufferRenderbufferEXT");
6687 glDisable(GL_SCISSOR_TEST
);
6688 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6691 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6692 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6693 checkGLcall("glBlitFramebuffer()");
6695 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6696 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6697 checkGLcall("glBlitFramebuffer()");
6700 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6702 if (This
->render_offscreen
) {
6703 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6705 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6706 checkGLcall("glBindFramebuffer()");
6709 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6710 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6711 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6712 glDrawBuffer(GL_BACK
);
6713 checkGLcall("glDrawBuffer()");
6718 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6719 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6720 WINED3DVIEWPORT viewport
;
6722 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6724 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6725 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6726 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6727 return WINED3DERR_INVALIDCALL
;
6730 /* MSDN says that null disables the render target
6731 but a device must always be associated with a render target
6732 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6734 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6735 FIXME("Trying to set render target 0 to NULL\n");
6736 return WINED3DERR_INVALIDCALL
;
6738 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6739 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
);
6740 return WINED3DERR_INVALIDCALL
;
6743 /* If we are trying to set what we already have, don't bother */
6744 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6745 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6748 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6749 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6750 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6752 /* Render target 0 is special */
6753 if(RenderTargetIndex
== 0) {
6754 /* Finally, reset the viewport as the MSDN states. */
6755 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6756 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6759 viewport
.MaxZ
= 1.0f
;
6760 viewport
.MinZ
= 0.0f
;
6761 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6762 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6763 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6765 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6770 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6771 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6772 HRESULT hr
= WINED3D_OK
;
6773 IWineD3DSurface
*tmp
;
6775 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6777 if (pNewZStencil
== This
->stencilBufferTarget
) {
6778 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6780 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6781 * depending on the renter target implementation being used.
6782 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6783 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6784 * stencil buffer and incur an extra memory overhead
6785 ******************************************************/
6787 if (This
->stencilBufferTarget
) {
6788 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6789 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6790 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6793 tmp
= This
->stencilBufferTarget
;
6794 This
->stencilBufferTarget
= pNewZStencil
;
6795 /* should we be calling the parent or the wined3d surface? */
6796 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6797 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6800 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6801 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6802 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6803 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6804 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6811 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6812 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6813 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6814 /* TODO: the use of Impl is deprecated. */
6815 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6816 WINED3DLOCKED_RECT lockedRect
;
6818 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6820 /* some basic validation checks */
6821 if(This
->cursorTexture
) {
6822 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6824 glDeleteTextures(1, &This
->cursorTexture
);
6826 This
->cursorTexture
= 0;
6829 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6830 This
->haveHardwareCursor
= TRUE
;
6832 This
->haveHardwareCursor
= FALSE
;
6835 WINED3DLOCKED_RECT rect
;
6837 /* MSDN: Cursor must be A8R8G8B8 */
6838 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6839 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6840 return WINED3DERR_INVALIDCALL
;
6843 /* MSDN: Cursor must be smaller than the display mode */
6844 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6845 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6846 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
);
6847 return WINED3DERR_INVALIDCALL
;
6850 if (!This
->haveHardwareCursor
) {
6851 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6853 /* Do not store the surface's pointer because the application may
6854 * release it after setting the cursor image. Windows doesn't
6855 * addref the set surface, so we can't do this either without
6856 * creating circular refcount dependencies. Copy out the gl texture
6859 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6860 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6861 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6863 const GlPixelFormatDesc
*glDesc
;
6864 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6865 char *mem
, *bits
= (char *)rect
.pBits
;
6866 GLint intfmt
= glDesc
->glInternal
;
6867 GLint format
= glDesc
->glFormat
;
6868 GLint type
= glDesc
->glType
;
6869 INT height
= This
->cursorHeight
;
6870 INT width
= This
->cursorWidth
;
6871 INT bpp
= tableEntry
->bpp
;
6874 /* Reformat the texture memory (pitch and width can be
6876 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6877 for(i
= 0; i
< height
; i
++)
6878 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6879 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6882 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6883 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6884 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6887 /* Make sure that a proper texture unit is selected */
6888 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6889 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6890 checkGLcall("glActiveTextureARB");
6892 sampler
= This
->rev_tex_unit_map
[0];
6893 if (sampler
!= -1) {
6894 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6896 /* Create a new cursor texture */
6897 glGenTextures(1, &This
->cursorTexture
);
6898 checkGLcall("glGenTextures");
6899 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6900 checkGLcall("glBindTexture");
6901 /* Copy the bitmap memory into the cursor texture */
6902 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6903 HeapFree(GetProcessHeap(), 0, mem
);
6904 checkGLcall("glTexImage2D");
6906 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6907 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6908 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6915 FIXME("A cursor texture was not returned.\n");
6916 This
->cursorTexture
= 0;
6921 /* Draw a hardware cursor */
6922 ICONINFO cursorInfo
;
6924 /* Create and clear maskBits because it is not needed for
6925 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6927 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6928 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6929 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6930 WINED3DLOCK_NO_DIRTY_UPDATE
|
6931 WINED3DLOCK_READONLY
6933 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6934 pSur
->currentDesc
.Height
);
6936 cursorInfo
.fIcon
= FALSE
;
6937 cursorInfo
.xHotspot
= XHotSpot
;
6938 cursorInfo
.yHotspot
= YHotSpot
;
6939 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6940 pSur
->currentDesc
.Height
, 1,
6942 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6943 pSur
->currentDesc
.Height
, 1,
6944 32, lockedRect
.pBits
);
6945 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6946 /* Create our cursor and clean up. */
6947 cursor
= CreateIconIndirect(&cursorInfo
);
6949 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6950 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6951 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6952 This
->hardwareCursor
= cursor
;
6953 HeapFree(GetProcessHeap(), 0, maskBits
);
6957 This
->xHotSpot
= XHotSpot
;
6958 This
->yHotSpot
= YHotSpot
;
6962 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6963 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6964 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6966 This
->xScreenSpace
= XScreenSpace
;
6967 This
->yScreenSpace
= YScreenSpace
;
6973 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6974 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6975 BOOL oldVisible
= This
->bCursorVisible
;
6978 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6981 * When ShowCursor is first called it should make the cursor appear at the OS's last
6982 * known cursor position. Because of this, some applications just repetitively call
6983 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6986 This
->xScreenSpace
= pt
.x
;
6987 This
->yScreenSpace
= pt
.y
;
6989 if (This
->haveHardwareCursor
) {
6990 This
->bCursorVisible
= bShow
;
6992 SetCursor(This
->hardwareCursor
);
6998 if (This
->cursorTexture
)
6999 This
->bCursorVisible
= bShow
;
7005 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
7006 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7007 IWineD3DResourceImpl
*resource
;
7008 TRACE("(%p) : state (%u)\n", This
, This
->state
);
7010 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7011 switch (This
->state
) {
7014 case WINED3DERR_DEVICELOST
:
7016 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7017 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
7018 return WINED3DERR_DEVICENOTRESET
;
7020 return WINED3DERR_DEVICELOST
;
7022 case WINED3DERR_DRIVERINTERNALERROR
:
7023 return WINED3DERR_DRIVERINTERNALERROR
;
7027 return WINED3DERR_DRIVERINTERNALERROR
;
7031 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
7032 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7033 /** FIXME: Resource tracking needs to be done,
7034 * The closes we can do to this is set the priorities of all managed textures low
7035 * and then reset them.
7036 ***********************************************************/
7037 FIXME("(%p) : stub\n", This
);
7041 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7042 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
7044 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7045 if(surface
->Flags
& SFLAG_DIBSECTION
) {
7046 /* Release the DC */
7047 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
7048 DeleteDC(surface
->hDC
);
7049 /* Release the DIB section */
7050 DeleteObject(surface
->dib
.DIBsection
);
7051 surface
->dib
.bitmap_data
= NULL
;
7052 surface
->resource
.allocatedMemory
= NULL
;
7053 surface
->Flags
&= ~SFLAG_DIBSECTION
;
7055 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
7056 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
7057 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
7058 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
7059 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
7060 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
7062 surface
->pow2Width
= surface
->pow2Height
= 1;
7063 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
7064 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
7066 surface
->glRect
.left
= 0;
7067 surface
->glRect
.top
= 0;
7068 surface
->glRect
.right
= surface
->pow2Width
;
7069 surface
->glRect
.bottom
= surface
->pow2Height
;
7071 if(surface
->glDescription
.textureName
) {
7072 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
7074 glDeleteTextures(1, &surface
->glDescription
.textureName
);
7076 surface
->glDescription
.textureName
= 0;
7077 surface
->Flags
&= ~SFLAG_CLIENT
;
7079 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
7080 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
7081 surface
->Flags
|= SFLAG_NONPOW2
;
7083 surface
->Flags
&= ~SFLAG_NONPOW2
;
7085 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
7086 surface
->resource
.allocatedMemory
= NULL
;
7087 surface
->resource
.heapMemory
= NULL
;
7088 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
7089 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7090 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
7091 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
7093 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
7097 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
7098 TRACE("Unloading resource %p\n", resource
);
7099 IWineD3DResource_UnLoad(resource
);
7100 IWineD3DResource_Release(resource
);
7104 static void reset_fbo_state(IWineD3DDevice
*iface
) {
7105 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7109 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
7110 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7113 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
7116 if (This
->src_fbo
) {
7117 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->src_fbo
));
7120 if (This
->dst_fbo
) {
7121 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->dst_fbo
));
7124 checkGLcall("Tear down FBOs\n");
7127 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7128 This
->fbo_color_attachments
[i
] = NULL
;
7130 This
->fbo_depth_attachment
= NULL
;
7133 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, WINED3DPRESENT_PARAMETERS
*pp
) {
7135 WINED3DDISPLAYMODE m
;
7138 /* All Windowed modes are supported, as is leaving the current mode */
7139 if(pp
->Windowed
) return TRUE
;
7140 if(!pp
->BackBufferWidth
) return TRUE
;
7141 if(!pp
->BackBufferHeight
) return TRUE
;
7143 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
7144 for(i
= 0; i
< count
; i
++) {
7145 memset(&m
, 0, sizeof(m
));
7146 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
7148 ERR("EnumAdapterModes failed\n");
7150 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
7151 /* Mode found, it is supported */
7155 /* Mode not found -> not supported */
7159 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7161 IWineD3DSwapChainImpl
*swapchain
;
7163 BOOL DisplayModeChanged
= FALSE
;
7164 WINED3DDISPLAYMODE mode
;
7165 IWineD3DBaseShaderImpl
*shader
;
7166 IWineD3DSurfaceImpl
*target
;
7168 TRACE("(%p)\n", This
);
7170 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7172 ERR("Failed to get the first implicit swapchain\n");
7176 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7177 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7178 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7179 pPresentationParameters
->BackBufferHeight
);
7180 return WINED3DERR_INVALIDCALL
;
7183 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7184 * on an existing gl context, so there's no real need for recreation.
7186 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7188 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7190 TRACE("New params:\n");
7191 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7192 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7193 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7194 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7195 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7196 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7197 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7198 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7199 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7200 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7201 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7202 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7203 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7205 /* No special treatment of these parameters. Just store them */
7206 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7207 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7208 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7209 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7211 /* What to do about these? */
7212 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7213 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7214 ERR("Cannot change the back buffer count yet\n");
7216 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7217 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7218 ERR("Cannot change the back buffer format yet\n");
7220 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7221 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7222 ERR("Cannot change the device window yet\n");
7224 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
7225 ERR("What do do about a changed auto depth stencil parameter?\n");
7228 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
7229 reset_fbo_state((IWineD3DDevice
*) This
);
7232 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
7233 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
7234 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
7238 if(This
->depth_blt_texture
) {
7239 glDeleteTextures(1, &This
->depth_blt_texture
);
7240 This
->depth_blt_texture
= 0;
7242 if (This
->depth_blt_rb
) {
7243 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
7244 This
->depth_blt_rb
= 0;
7245 This
->depth_blt_rb_w
= 0;
7246 This
->depth_blt_rb_h
= 0;
7248 This
->shader_backend
->shader_free_private(iface
);
7249 This
->frag_pipe
->free_private(iface
);
7251 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
7252 /* Textures are recreated below */
7253 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
7254 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7255 This
->dummyTextureName
[i
] = 0;
7259 while(This
->numContexts
) {
7260 DestroyContext(This
, This
->contexts
[0]);
7262 This
->activeContext
= NULL
;
7263 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
7264 swapchain
->context
= NULL
;
7265 swapchain
->num_contexts
= 0;
7267 if(pPresentationParameters
->Windowed
) {
7268 mode
.Width
= swapchain
->orig_width
;
7269 mode
.Height
= swapchain
->orig_height
;
7270 mode
.RefreshRate
= 0;
7271 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7273 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7274 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7275 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7276 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7279 /* Should Width == 800 && Height == 0 set 800x600? */
7280 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7281 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7282 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7289 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
7290 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
7294 if(!pPresentationParameters
->Windowed
) {
7295 DisplayModeChanged
= TRUE
;
7297 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7298 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7300 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7301 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7302 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7304 if(This
->auto_depth_stencil_buffer
) {
7305 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7309 /* Now set the new viewport */
7310 IWineD3DDevice_SetViewport(iface
, &vp
);
7313 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7314 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7315 DisplayModeChanged
) {
7317 IWineD3DDevice_SetFullscreen(iface
, !pPresentationParameters
->Windowed
);
7318 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7319 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7320 } else if(!pPresentationParameters
->Windowed
) {
7321 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7322 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7323 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7324 * Reset to clear up their mess. Guild Wars also loses the device during that.
7328 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
7329 This
->style
= style
;
7330 This
->exStyle
= exStyle
;
7333 /* Recreate the primary swapchain's context */
7334 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
7335 if(swapchain
->backBuffer
) {
7336 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
7338 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
7340 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
7341 &swapchain
->presentParms
);
7342 swapchain
->num_contexts
= 1;
7343 This
->activeContext
= swapchain
->context
[0];
7344 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7346 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7348 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7350 create_dummy_textures(This
);
7353 hr
= This
->shader_backend
->shader_alloc_private(iface
);
7355 ERR("Failed to recreate shader private data\n");
7358 hr
= This
->frag_pipe
->alloc_private(iface
);
7360 TRACE("Fragment pipeline private data couldn't be allocated\n");
7364 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7370 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7371 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7372 /** FIXME: always true at the moment **/
7373 if(!bEnableDialogs
) {
7374 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7380 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7381 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7382 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7384 *pParameters
= This
->createParms
;
7388 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7389 IWineD3DSwapChain
*swapchain
;
7391 TRACE("Relaying to swapchain\n");
7393 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7394 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
7395 IWineD3DSwapChain_Release(swapchain
);
7400 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7401 IWineD3DSwapChain
*swapchain
;
7403 TRACE("Relaying to swapchain\n");
7405 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7406 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7407 IWineD3DSwapChain_Release(swapchain
);
7413 /** ********************************************************
7414 * Notification functions
7415 ** ********************************************************/
7416 /** This function must be called in the release of a resource when ref == 0,
7417 * the contents of resource must still be correct,
7418 * any handles to other resource held by the caller must be closed
7419 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7420 *****************************************************/
7421 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7422 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7424 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7425 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7428 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7429 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7431 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7433 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7437 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7438 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7441 TRACE("(%p) : resource %p\n", This
, resource
);
7442 switch(IWineD3DResource_GetType(resource
)){
7443 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7444 case WINED3DRTYPE_SURFACE
: {
7447 /* Cleanup any FBO attachments if d3d is enabled */
7448 if(This
->d3d_initialized
) {
7449 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7450 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7452 TRACE("Last active render target destroyed\n");
7453 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7454 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7455 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7456 * and the lastActiveRenderTarget member shouldn't matter
7459 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7460 TRACE("Activating primary back buffer\n");
7461 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7462 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7463 /* Single buffering environment */
7464 TRACE("Activating primary front buffer\n");
7465 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7467 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7468 /* Implicit render target destroyed, that means the device is being destroyed
7469 * whatever we set here, it shouldn't matter
7471 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7474 /* May happen during ddraw uninitialization */
7475 TRACE("Render target set, but swapchain does not exist!\n");
7476 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7481 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7482 if (This
->fbo_color_attachments
[i
] == (IWineD3DSurface
*)resource
) {
7483 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
7484 set_render_target_fbo(iface
, i
, NULL
);
7485 This
->fbo_color_attachments
[i
] = NULL
;
7488 if (This
->fbo_depth_attachment
== (IWineD3DSurface
*)resource
) {
7489 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
7490 set_depth_stencil_fbo(iface
, NULL
);
7491 This
->fbo_depth_attachment
= NULL
;
7498 case WINED3DRTYPE_TEXTURE
:
7499 case WINED3DRTYPE_CUBETEXTURE
:
7500 case WINED3DRTYPE_VOLUMETEXTURE
:
7501 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7502 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7503 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7504 This
->stateBlock
->textures
[counter
] = NULL
;
7506 if (This
->updateStateBlock
!= This
->stateBlock
){
7507 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7508 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7509 This
->updateStateBlock
->textures
[counter
] = NULL
;
7514 case WINED3DRTYPE_VOLUME
:
7515 /* TODO: nothing really? */
7517 case WINED3DRTYPE_VERTEXBUFFER
:
7518 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7521 TRACE("Cleaning up stream pointers\n");
7523 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7524 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7525 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7527 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7528 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7529 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7530 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7531 /* Set changed flag? */
7534 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) */
7535 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7536 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7537 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7540 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7541 else { /* This shouldn't happen */
7542 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7549 case WINED3DRTYPE_INDEXBUFFER
:
7550 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7551 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7552 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7553 This
->updateStateBlock
->pIndexData
= NULL
;
7556 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7557 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7558 This
->stateBlock
->pIndexData
= NULL
;
7564 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7569 /* Remove the resource from the resourceStore */
7570 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7572 TRACE("Resource released\n");
7576 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7577 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7578 IWineD3DResourceImpl
*resource
, *cursor
;
7580 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7582 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7583 TRACE("enumerating resource %p\n", resource
);
7584 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7585 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7586 if(ret
== S_FALSE
) {
7587 TRACE("Canceling enumeration\n");
7594 /**********************************************************
7595 * IWineD3DDevice VTbl follows
7596 **********************************************************/
7598 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7600 /*** IUnknown methods ***/
7601 IWineD3DDeviceImpl_QueryInterface
,
7602 IWineD3DDeviceImpl_AddRef
,
7603 IWineD3DDeviceImpl_Release
,
7604 /*** IWineD3DDevice methods ***/
7605 IWineD3DDeviceImpl_GetParent
,
7606 /*** Creation methods**/
7607 IWineD3DDeviceImpl_CreateVertexBuffer
,
7608 IWineD3DDeviceImpl_CreateIndexBuffer
,
7609 IWineD3DDeviceImpl_CreateStateBlock
,
7610 IWineD3DDeviceImpl_CreateSurface
,
7611 IWineD3DDeviceImpl_CreateTexture
,
7612 IWineD3DDeviceImpl_CreateVolumeTexture
,
7613 IWineD3DDeviceImpl_CreateVolume
,
7614 IWineD3DDeviceImpl_CreateCubeTexture
,
7615 IWineD3DDeviceImpl_CreateQuery
,
7616 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7617 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7618 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7619 IWineD3DDeviceImpl_CreateVertexShader
,
7620 IWineD3DDeviceImpl_CreatePixelShader
,
7621 IWineD3DDeviceImpl_CreatePalette
,
7622 /*** Odd functions **/
7623 IWineD3DDeviceImpl_Init3D
,
7624 IWineD3DDeviceImpl_Uninit3D
,
7625 IWineD3DDeviceImpl_SetFullscreen
,
7626 IWineD3DDeviceImpl_SetMultithreaded
,
7627 IWineD3DDeviceImpl_EvictManagedResources
,
7628 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7629 IWineD3DDeviceImpl_GetBackBuffer
,
7630 IWineD3DDeviceImpl_GetCreationParameters
,
7631 IWineD3DDeviceImpl_GetDeviceCaps
,
7632 IWineD3DDeviceImpl_GetDirect3D
,
7633 IWineD3DDeviceImpl_GetDisplayMode
,
7634 IWineD3DDeviceImpl_SetDisplayMode
,
7635 IWineD3DDeviceImpl_GetHWND
,
7636 IWineD3DDeviceImpl_SetHWND
,
7637 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7638 IWineD3DDeviceImpl_GetRasterStatus
,
7639 IWineD3DDeviceImpl_GetSwapChain
,
7640 IWineD3DDeviceImpl_Reset
,
7641 IWineD3DDeviceImpl_SetDialogBoxMode
,
7642 IWineD3DDeviceImpl_SetCursorProperties
,
7643 IWineD3DDeviceImpl_SetCursorPosition
,
7644 IWineD3DDeviceImpl_ShowCursor
,
7645 IWineD3DDeviceImpl_TestCooperativeLevel
,
7646 /*** Getters and setters **/
7647 IWineD3DDeviceImpl_SetClipPlane
,
7648 IWineD3DDeviceImpl_GetClipPlane
,
7649 IWineD3DDeviceImpl_SetClipStatus
,
7650 IWineD3DDeviceImpl_GetClipStatus
,
7651 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7652 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7653 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7654 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7655 IWineD3DDeviceImpl_SetFVF
,
7656 IWineD3DDeviceImpl_GetFVF
,
7657 IWineD3DDeviceImpl_SetGammaRamp
,
7658 IWineD3DDeviceImpl_GetGammaRamp
,
7659 IWineD3DDeviceImpl_SetIndices
,
7660 IWineD3DDeviceImpl_GetIndices
,
7661 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7662 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7663 IWineD3DDeviceImpl_SetLight
,
7664 IWineD3DDeviceImpl_GetLight
,
7665 IWineD3DDeviceImpl_SetLightEnable
,
7666 IWineD3DDeviceImpl_GetLightEnable
,
7667 IWineD3DDeviceImpl_SetMaterial
,
7668 IWineD3DDeviceImpl_GetMaterial
,
7669 IWineD3DDeviceImpl_SetNPatchMode
,
7670 IWineD3DDeviceImpl_GetNPatchMode
,
7671 IWineD3DDeviceImpl_SetPaletteEntries
,
7672 IWineD3DDeviceImpl_GetPaletteEntries
,
7673 IWineD3DDeviceImpl_SetPixelShader
,
7674 IWineD3DDeviceImpl_GetPixelShader
,
7675 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7676 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7677 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7678 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7679 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7680 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7681 IWineD3DDeviceImpl_SetRenderState
,
7682 IWineD3DDeviceImpl_GetRenderState
,
7683 IWineD3DDeviceImpl_SetRenderTarget
,
7684 IWineD3DDeviceImpl_GetRenderTarget
,
7685 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7686 IWineD3DDeviceImpl_SetSamplerState
,
7687 IWineD3DDeviceImpl_GetSamplerState
,
7688 IWineD3DDeviceImpl_SetScissorRect
,
7689 IWineD3DDeviceImpl_GetScissorRect
,
7690 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7691 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7692 IWineD3DDeviceImpl_SetStreamSource
,
7693 IWineD3DDeviceImpl_GetStreamSource
,
7694 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7695 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7696 IWineD3DDeviceImpl_SetTexture
,
7697 IWineD3DDeviceImpl_GetTexture
,
7698 IWineD3DDeviceImpl_SetTextureStageState
,
7699 IWineD3DDeviceImpl_GetTextureStageState
,
7700 IWineD3DDeviceImpl_SetTransform
,
7701 IWineD3DDeviceImpl_GetTransform
,
7702 IWineD3DDeviceImpl_SetVertexDeclaration
,
7703 IWineD3DDeviceImpl_GetVertexDeclaration
,
7704 IWineD3DDeviceImpl_SetVertexShader
,
7705 IWineD3DDeviceImpl_GetVertexShader
,
7706 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7707 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7708 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7709 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7710 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7711 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7712 IWineD3DDeviceImpl_SetViewport
,
7713 IWineD3DDeviceImpl_GetViewport
,
7714 IWineD3DDeviceImpl_MultiplyTransform
,
7715 IWineD3DDeviceImpl_ValidateDevice
,
7716 IWineD3DDeviceImpl_ProcessVertices
,
7717 /*** State block ***/
7718 IWineD3DDeviceImpl_BeginStateBlock
,
7719 IWineD3DDeviceImpl_EndStateBlock
,
7720 /*** Scene management ***/
7721 IWineD3DDeviceImpl_BeginScene
,
7722 IWineD3DDeviceImpl_EndScene
,
7723 IWineD3DDeviceImpl_Present
,
7724 IWineD3DDeviceImpl_Clear
,
7726 IWineD3DDeviceImpl_DrawPrimitive
,
7727 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7728 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7729 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7730 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7731 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7732 IWineD3DDeviceImpl_DrawRectPatch
,
7733 IWineD3DDeviceImpl_DrawTriPatch
,
7734 IWineD3DDeviceImpl_DeletePatch
,
7735 IWineD3DDeviceImpl_ColorFill
,
7736 IWineD3DDeviceImpl_UpdateTexture
,
7737 IWineD3DDeviceImpl_UpdateSurface
,
7738 IWineD3DDeviceImpl_GetFrontBufferData
,
7739 /*** object tracking ***/
7740 IWineD3DDeviceImpl_ResourceReleased
,
7741 IWineD3DDeviceImpl_EnumResources
7744 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl
=
7746 /*** IUnknown methods ***/
7747 IWineD3DDeviceImpl_QueryInterface
,
7748 IWineD3DDeviceImpl_AddRef
,
7749 IWineD3DDeviceImpl_Release
,
7750 /*** IWineD3DDevice methods ***/
7751 IWineD3DDeviceImpl_GetParent
,
7752 /*** Creation methods**/
7753 IWineD3DDeviceImpl_CreateVertexBuffer
,
7754 IWineD3DDeviceImpl_CreateIndexBuffer
,
7755 IWineD3DDeviceImpl_CreateStateBlock
,
7756 IWineD3DDeviceImpl_CreateSurface
,
7757 IWineD3DDeviceImpl_CreateTexture
,
7758 IWineD3DDeviceImpl_CreateVolumeTexture
,
7759 IWineD3DDeviceImpl_CreateVolume
,
7760 IWineD3DDeviceImpl_CreateCubeTexture
,
7761 IWineD3DDeviceImpl_CreateQuery
,
7762 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7763 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7764 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7765 IWineD3DDeviceImpl_CreateVertexShader
,
7766 IWineD3DDeviceImpl_CreatePixelShader
,
7767 IWineD3DDeviceImpl_CreatePalette
,
7768 /*** Odd functions **/
7769 IWineD3DDeviceImpl_Init3D
,
7770 IWineD3DDeviceImpl_Uninit3D
,
7771 IWineD3DDeviceImpl_SetFullscreen
,
7772 IWineD3DDeviceImpl_SetMultithreaded
,
7773 IWineD3DDeviceImpl_EvictManagedResources
,
7774 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7775 IWineD3DDeviceImpl_GetBackBuffer
,
7776 IWineD3DDeviceImpl_GetCreationParameters
,
7777 IWineD3DDeviceImpl_GetDeviceCaps
,
7778 IWineD3DDeviceImpl_GetDirect3D
,
7779 IWineD3DDeviceImpl_GetDisplayMode
,
7780 IWineD3DDeviceImpl_SetDisplayMode
,
7781 IWineD3DDeviceImpl_GetHWND
,
7782 IWineD3DDeviceImpl_SetHWND
,
7783 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7784 IWineD3DDeviceImpl_GetRasterStatus
,
7785 IWineD3DDeviceImpl_GetSwapChain
,
7786 IWineD3DDeviceImpl_Reset
,
7787 IWineD3DDeviceImpl_SetDialogBoxMode
,
7788 IWineD3DDeviceImpl_SetCursorProperties
,
7789 IWineD3DDeviceImpl_SetCursorPosition
,
7790 IWineD3DDeviceImpl_ShowCursor
,
7791 IWineD3DDeviceImpl_TestCooperativeLevel
,
7792 /*** Getters and setters **/
7793 IWineD3DDeviceImpl_SetClipPlane
,
7794 IWineD3DDeviceImpl_GetClipPlane
,
7795 IWineD3DDeviceImpl_SetClipStatus
,
7796 IWineD3DDeviceImpl_GetClipStatus
,
7797 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7798 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7799 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7800 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7801 IWineD3DDeviceImpl_SetFVF
,
7802 IWineD3DDeviceImpl_GetFVF
,
7803 IWineD3DDeviceImpl_SetGammaRamp
,
7804 IWineD3DDeviceImpl_GetGammaRamp
,
7805 IWineD3DDeviceImpl_SetIndices
,
7806 IWineD3DDeviceImpl_GetIndices
,
7807 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7808 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7809 IWineD3DDeviceImpl_SetLight
,
7810 IWineD3DDeviceImpl_GetLight
,
7811 IWineD3DDeviceImpl_SetLightEnable
,
7812 IWineD3DDeviceImpl_GetLightEnable
,
7813 IWineD3DDeviceImpl_SetMaterial
,
7814 IWineD3DDeviceImpl_GetMaterial
,
7815 IWineD3DDeviceImpl_SetNPatchMode
,
7816 IWineD3DDeviceImpl_GetNPatchMode
,
7817 IWineD3DDeviceImpl_SetPaletteEntries
,
7818 IWineD3DDeviceImpl_GetPaletteEntries
,
7819 IWineD3DDeviceImpl_SetPixelShader
,
7820 IWineD3DDeviceImpl_GetPixelShader
,
7821 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7822 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7823 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7824 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7825 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst
,
7826 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7827 IWineD3DDeviceImpl_SetRenderState
,
7828 IWineD3DDeviceImpl_GetRenderState
,
7829 IWineD3DDeviceImpl_SetRenderTarget
,
7830 IWineD3DDeviceImpl_GetRenderTarget
,
7831 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7832 IWineD3DDeviceImpl_SetSamplerState
,
7833 IWineD3DDeviceImpl_GetSamplerState
,
7834 IWineD3DDeviceImpl_SetScissorRect
,
7835 IWineD3DDeviceImpl_GetScissorRect
,
7836 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7837 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7838 IWineD3DDeviceImpl_SetStreamSource
,
7839 IWineD3DDeviceImpl_GetStreamSource
,
7840 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7841 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7842 IWineD3DDeviceImpl_SetTexture
,
7843 IWineD3DDeviceImpl_GetTexture
,
7844 IWineD3DDeviceImpl_SetTextureStageState
,
7845 IWineD3DDeviceImpl_GetTextureStageState
,
7846 IWineD3DDeviceImpl_SetTransform
,
7847 IWineD3DDeviceImpl_GetTransform
,
7848 IWineD3DDeviceImpl_SetVertexDeclaration
,
7849 IWineD3DDeviceImpl_GetVertexDeclaration
,
7850 IWineD3DDeviceImpl_SetVertexShader
,
7851 IWineD3DDeviceImpl_GetVertexShader
,
7852 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7853 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7854 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7855 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7856 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst
,
7857 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7858 IWineD3DDeviceImpl_SetViewport
,
7859 IWineD3DDeviceImpl_GetViewport
,
7860 IWineD3DDeviceImpl_MultiplyTransform
,
7861 IWineD3DDeviceImpl_ValidateDevice
,
7862 IWineD3DDeviceImpl_ProcessVertices
,
7863 /*** State block ***/
7864 IWineD3DDeviceImpl_BeginStateBlock
,
7865 IWineD3DDeviceImpl_EndStateBlock
,
7866 /*** Scene management ***/
7867 IWineD3DDeviceImpl_BeginScene
,
7868 IWineD3DDeviceImpl_EndScene
,
7869 IWineD3DDeviceImpl_Present
,
7870 IWineD3DDeviceImpl_Clear
,
7872 IWineD3DDeviceImpl_DrawPrimitive
,
7873 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7874 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7875 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7876 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7877 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7878 IWineD3DDeviceImpl_DrawRectPatch
,
7879 IWineD3DDeviceImpl_DrawTriPatch
,
7880 IWineD3DDeviceImpl_DeletePatch
,
7881 IWineD3DDeviceImpl_ColorFill
,
7882 IWineD3DDeviceImpl_UpdateTexture
,
7883 IWineD3DDeviceImpl_UpdateSurface
,
7884 IWineD3DDeviceImpl_GetFrontBufferData
,
7885 /*** object tracking ***/
7886 IWineD3DDeviceImpl_ResourceReleased
,
7887 IWineD3DDeviceImpl_EnumResources
7890 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7891 WINED3DRS_ALPHABLENDENABLE
,
7892 WINED3DRS_ALPHAFUNC
,
7893 WINED3DRS_ALPHAREF
,
7894 WINED3DRS_ALPHATESTENABLE
,
7896 WINED3DRS_COLORWRITEENABLE
,
7897 WINED3DRS_DESTBLEND
,
7898 WINED3DRS_DITHERENABLE
,
7899 WINED3DRS_FILLMODE
,
7900 WINED3DRS_FOGDENSITY
,
7902 WINED3DRS_FOGSTART
,
7903 WINED3DRS_LASTPIXEL
,
7904 WINED3DRS_SHADEMODE
,
7905 WINED3DRS_SRCBLEND
,
7906 WINED3DRS_STENCILENABLE
,
7907 WINED3DRS_STENCILFAIL
,
7908 WINED3DRS_STENCILFUNC
,
7909 WINED3DRS_STENCILMASK
,
7910 WINED3DRS_STENCILPASS
,
7911 WINED3DRS_STENCILREF
,
7912 WINED3DRS_STENCILWRITEMASK
,
7913 WINED3DRS_STENCILZFAIL
,
7914 WINED3DRS_TEXTUREFACTOR
,
7925 WINED3DRS_ZWRITEENABLE
7928 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7929 WINED3DTSS_ADDRESSW
,
7930 WINED3DTSS_ALPHAARG0
,
7931 WINED3DTSS_ALPHAARG1
,
7932 WINED3DTSS_ALPHAARG2
,
7933 WINED3DTSS_ALPHAOP
,
7934 WINED3DTSS_BUMPENVLOFFSET
,
7935 WINED3DTSS_BUMPENVLSCALE
,
7936 WINED3DTSS_BUMPENVMAT00
,
7937 WINED3DTSS_BUMPENVMAT01
,
7938 WINED3DTSS_BUMPENVMAT10
,
7939 WINED3DTSS_BUMPENVMAT11
,
7940 WINED3DTSS_COLORARG0
,
7941 WINED3DTSS_COLORARG1
,
7942 WINED3DTSS_COLORARG2
,
7943 WINED3DTSS_COLOROP
,
7944 WINED3DTSS_RESULTARG
,
7945 WINED3DTSS_TEXCOORDINDEX
,
7946 WINED3DTSS_TEXTURETRANSFORMFLAGS
7949 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7950 WINED3DSAMP_ADDRESSU
,
7951 WINED3DSAMP_ADDRESSV
,
7952 WINED3DSAMP_ADDRESSW
,
7953 WINED3DSAMP_BORDERCOLOR
,
7954 WINED3DSAMP_MAGFILTER
,
7955 WINED3DSAMP_MINFILTER
,
7956 WINED3DSAMP_MIPFILTER
,
7957 WINED3DSAMP_MIPMAPLODBIAS
,
7958 WINED3DSAMP_MAXMIPLEVEL
,
7959 WINED3DSAMP_MAXANISOTROPY
,
7960 WINED3DSAMP_SRGBTEXTURE
,
7961 WINED3DSAMP_ELEMENTINDEX
7964 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7966 WINED3DRS_AMBIENTMATERIALSOURCE
,
7967 WINED3DRS_CLIPPING
,
7968 WINED3DRS_CLIPPLANEENABLE
,
7969 WINED3DRS_COLORVERTEX
,
7970 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7971 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7972 WINED3DRS_FOGDENSITY
,
7974 WINED3DRS_FOGSTART
,
7975 WINED3DRS_FOGTABLEMODE
,
7976 WINED3DRS_FOGVERTEXMODE
,
7977 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7978 WINED3DRS_LIGHTING
,
7979 WINED3DRS_LOCALVIEWER
,
7980 WINED3DRS_MULTISAMPLEANTIALIAS
,
7981 WINED3DRS_MULTISAMPLEMASK
,
7982 WINED3DRS_NORMALIZENORMALS
,
7983 WINED3DRS_PATCHEDGESTYLE
,
7984 WINED3DRS_POINTSCALE_A
,
7985 WINED3DRS_POINTSCALE_B
,
7986 WINED3DRS_POINTSCALE_C
,
7987 WINED3DRS_POINTSCALEENABLE
,
7988 WINED3DRS_POINTSIZE
,
7989 WINED3DRS_POINTSIZE_MAX
,
7990 WINED3DRS_POINTSIZE_MIN
,
7991 WINED3DRS_POINTSPRITEENABLE
,
7992 WINED3DRS_RANGEFOGENABLE
,
7993 WINED3DRS_SPECULARMATERIALSOURCE
,
7994 WINED3DRS_TWEENFACTOR
,
7995 WINED3DRS_VERTEXBLEND
,
7996 WINED3DRS_CULLMODE
,
8000 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
8001 WINED3DTSS_TEXCOORDINDEX
,
8002 WINED3DTSS_TEXTURETRANSFORMFLAGS
8005 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
8006 WINED3DSAMP_DMAPOFFSET
8009 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
8010 DWORD rep
= This
->StateTable
[state
].representative
;
8014 WineD3DContext
*context
;
8017 for(i
= 0; i
< This
->numContexts
; i
++) {
8018 context
= This
->contexts
[i
];
8019 if(isStateDirty(context
, rep
)) continue;
8021 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
8024 context
->isStateDirty
[idx
] |= (1 << shift
);
8028 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8029 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
8030 /* The drawable size of a pbuffer render target is the current pbuffer size
8032 *width
= dev
->pbufferWidth
;
8033 *height
= dev
->pbufferHeight
;
8036 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8037 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8039 *width
= This
->pow2Width
;
8040 *height
= This
->pow2Height
;
8043 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8044 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
8045 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8046 * current context's drawable, which is the size of the back buffer of the swapchain
8047 * the active context belongs to. The back buffer of the swapchain is stored as the
8048 * surface the context belongs to.
8050 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
8051 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;