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-2007 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; \
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 + 4)); \
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 = object->resource.heapMemory; \
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 if (This
->glsl_program_lookup
) hash_table_destroy(This
->glsl_program_lookup
);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (This
->resources
!= NULL
) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
184 dumpResources(This
->resources
);
187 if(This
->contexts
) ERR("Context array not freed!\n");
188 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
189 This
->haveHardwareCursor
= FALSE
;
191 IWineD3D_Release(This
->wineD3D
);
192 This
->wineD3D
= NULL
;
193 HeapFree(GetProcessHeap(), 0, This
);
194 TRACE("Freed device %p\n", This
);
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
204 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
205 *pParent
= This
->parent
;
206 IUnknown_AddRef(This
->parent
);
210 static void CreateVBO(IWineD3DVertexBufferImpl
*object
) {
211 IWineD3DDeviceImpl
*This
= object
->resource
.wineD3DDevice
; /* Needed for GL_EXTCALL */
212 GLenum error
, glUsage
;
213 DWORD vboUsage
= object
->resource
.usage
;
214 if(object
->Flags
& VBFLAG_VBOCREATEFAIL
) {
215 WARN("Creating a vbo failed once, not trying again\n");
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object
, debug_d3dusage(vboUsage
));
221 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
222 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
225 /* Make sure that the gl error is cleared. Do not use checkGLcall
226 * here because checkGLcall just prints a fixme and continues. However,
227 * if an error during VBO creation occurs we can fall back to non-vbo operation
228 * with full functionality(but performance loss)
230 while(glGetError() != GL_NO_ERROR
);
232 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
233 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
234 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
235 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
236 * to check if the rhw and color values are in the correct format.
239 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
240 error
= glGetError();
241 if(object
->vbo
== 0 || error
!= GL_NO_ERROR
) {
242 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error
), error
);
246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, object
->vbo
));
247 error
= glGetError();
248 if(error
!= GL_NO_ERROR
) {
249 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error
), error
);
253 /* Don't use static, because dx apps tend to update the buffer
254 * quite often even if they specify 0 usage. Because we always keep the local copy
255 * we never read from the vbo and can create a write only opengl buffer.
257 switch(vboUsage
& (WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
) ) {
258 case WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
:
259 case WINED3DUSAGE_DYNAMIC
:
260 TRACE("Gl usage = GL_STREAM_DRAW\n");
261 glUsage
= GL_STREAM_DRAW_ARB
;
263 case WINED3DUSAGE_WRITEONLY
:
265 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
266 glUsage
= GL_DYNAMIC_DRAW_ARB
;
270 /* Reserve memory for the buffer. The amount of data won't change
271 * so we are safe with calling glBufferData once with a NULL ptr and
272 * calling glBufferSubData on updates
274 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
275 error
= glGetError();
276 if(error
!= GL_NO_ERROR
) {
277 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error
), error
);
285 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
286 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
287 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
289 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
294 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
295 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
297 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
298 IWineD3DVertexBufferImpl
*object
;
299 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
300 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
304 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
305 *ppVertexBuffer
= NULL
;
306 return WINED3DERR_INVALIDCALL
;
309 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
311 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
312 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
316 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
317 * drawStridedFast (half-life 2).
319 * Basically converting the vertices in the buffer is quite expensive, and observations
320 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
321 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
323 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
324 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
325 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
326 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
328 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
329 * more. In this call we can convert dx7 buffers too.
331 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
332 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
) && Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) &&
333 (dxVersion
> 7 || !conv
) ) {
339 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
340 GLenum error
, glUsage
;
341 TRACE("Creating VBO for Index Buffer %p\n", object
);
343 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
344 * restored on the next draw
346 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
348 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
349 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
354 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
355 error
= glGetError();
356 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
357 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
361 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
362 error
= glGetError();
363 if(error
!= GL_NO_ERROR
) {
364 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
368 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
369 * copy no readback will be needed
371 glUsage
= GL_STATIC_DRAW_ARB
;
372 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
373 error
= glGetError();
374 if(error
!= GL_NO_ERROR
) {
375 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
379 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
383 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
384 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
389 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
390 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
391 HANDLE
*sharedHandle
, IUnknown
*parent
) {
392 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
393 IWineD3DIndexBufferImpl
*object
;
394 TRACE("(%p) Creating index buffer\n", This
);
396 /* Allocate the storage for the device */
397 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
399 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
400 CreateIndexBufferVBO(This
, object
);
403 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
404 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
405 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
410 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
412 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
413 IWineD3DStateBlockImpl
*object
;
417 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
418 object
->blockType
= Type
;
420 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
421 list_init(&object
->lightMap
[i
]);
424 /* Special case - Used during initialization to produce a placeholder stateblock
425 so other functions called can update a state block */
426 if (Type
== WINED3DSBT_INIT
) {
427 /* Don't bother increasing the reference count otherwise a device will never
428 be freed due to circular dependencies */
432 temp_result
= allocate_shader_constants(object
);
433 if (WINED3D_OK
!= temp_result
)
436 /* Otherwise, might as well set the whole state block to the appropriate values */
437 if (This
->stateBlock
!= NULL
)
438 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
440 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
442 /* Reset the ref and type after kludging it */
443 object
->wineD3DDevice
= This
;
445 object
->blockType
= Type
;
447 TRACE("Updating changed flags appropriate for type %d\n", Type
);
449 if (Type
== WINED3DSBT_ALL
) {
451 TRACE("ALL => Pretend everything has changed\n");
452 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
454 /* Lights are not part of the changed / set structure */
455 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
457 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
458 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
459 light
->changed
= TRUE
;
460 light
->enabledChanged
= TRUE
;
463 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
464 object
->contained_render_states
[j
- 1] = j
;
466 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
467 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
468 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
469 object
->contained_transform_states
[j
- 1] = j
;
471 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
472 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
473 object
->contained_vs_consts_f
[j
] = j
;
475 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
476 for(j
= 0; j
< MAX_CONST_I
; j
++) {
477 object
->contained_vs_consts_i
[j
] = j
;
479 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
480 for(j
= 0; j
< MAX_CONST_B
; j
++) {
481 object
->contained_vs_consts_b
[j
] = j
;
483 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
484 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
485 object
->contained_ps_consts_f
[j
] = j
;
487 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
488 for(j
= 0; j
< MAX_CONST_I
; j
++) {
489 object
->contained_ps_consts_i
[j
] = j
;
491 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
492 for(j
= 0; j
< MAX_CONST_B
; j
++) {
493 object
->contained_ps_consts_b
[j
] = j
;
495 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
496 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
497 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
498 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
499 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
500 object
->num_contained_tss_states
++;
503 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
504 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
505 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
506 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
507 object
->num_contained_sampler_states
++;
511 for(i
= 0; i
< MAX_STREAMS
; i
++) {
512 if(object
->streamSource
[i
]) {
513 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
516 if(object
->pIndexData
) {
517 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
519 if(object
->vertexShader
) {
520 IWineD3DVertexShader_AddRef(object
->vertexShader
);
522 if(object
->pixelShader
) {
523 IWineD3DPixelShader_AddRef(object
->pixelShader
);
526 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
528 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
529 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
531 object
->changed
.pixelShader
= TRUE
;
533 /* Pixel Shader Constants */
534 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
535 object
->contained_ps_consts_f
[i
] = i
;
536 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
538 object
->num_contained_ps_consts_f
= GL_LIMITS(vshader_constantsF
);
539 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
540 object
->contained_ps_consts_b
[i
] = i
;
541 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
543 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
544 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
545 object
->contained_ps_consts_i
[i
] = i
;
546 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
548 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
550 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
551 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
552 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
554 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
555 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
556 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
557 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
558 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
559 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
560 object
->num_contained_tss_states
++;
563 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
564 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
565 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
566 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
567 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
568 object
->num_contained_sampler_states
++;
571 if(object
->pixelShader
) {
572 IWineD3DPixelShader_AddRef(object
->pixelShader
);
575 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
576 * on them. This makes releasing the buffer easier
578 for(i
= 0; i
< MAX_STREAMS
; i
++) {
579 object
->streamSource
[i
] = NULL
;
581 object
->pIndexData
= NULL
;
582 object
->vertexShader
= NULL
;
584 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
586 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
587 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
589 object
->changed
.vertexShader
= TRUE
;
591 /* Vertex Shader Constants */
592 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
593 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
594 object
->contained_vs_consts_f
[i
] = i
;
596 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
597 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
598 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
599 object
->contained_vs_consts_b
[i
] = i
;
601 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
602 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
603 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
604 object
->contained_vs_consts_i
[i
] = i
;
606 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
607 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
608 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
609 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
611 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
612 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
613 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
614 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
615 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
616 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
617 object
->num_contained_tss_states
++;
620 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
621 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
622 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
623 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
624 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
625 object
->num_contained_sampler_states
++;
629 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
631 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
632 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
633 light
->changed
= TRUE
;
634 light
->enabledChanged
= TRUE
;
638 for(i
= 0; i
< MAX_STREAMS
; i
++) {
639 if(object
->streamSource
[i
]) {
640 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
643 if(object
->vertexShader
) {
644 IWineD3DVertexShader_AddRef(object
->vertexShader
);
646 object
->pIndexData
= NULL
;
647 object
->pixelShader
= NULL
;
649 FIXME("Unrecognized state block type %d\n", Type
);
652 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
656 /* ************************************
658 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
661 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
663 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.
665 ******************************** */
667 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
) {
668 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
669 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
670 unsigned int Size
= 1;
671 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, NULL
, NULL
);
672 TRACE("(%p) Create surface\n",This
);
674 /** FIXME: Check ranges on the inputs are valid
677 * [in] Quality level. The valid range is between zero and one less than the level
678 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
679 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
680 * values of paired render targets, depth stencil surfaces, and the MultiSample type
682 *******************************/
687 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
689 * If this flag is set, the contents of the depth stencil buffer will be
690 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
691 * with a different depth surface.
693 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
694 ***************************/
696 if(MultisampleQuality
< 0) {
697 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
698 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
701 if(MultisampleQuality
> 0) {
702 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
703 MultisampleQuality
=0;
706 /** FIXME: Check that the format is supported
708 *******************************/
710 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
711 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
713 *********************************/
714 if (WINED3DFMT_UNKNOWN
== Format
) {
716 } else if (Format
== WINED3DFMT_DXT1
) {
717 /* DXT1 is half byte per pixel */
718 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
720 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
721 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
722 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
724 /* The pitch is a multiple of 4 bytes */
725 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
729 /** Create and initialise the surface resource **/
730 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
731 /* "Standalone" surface */
732 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
734 object
->currentDesc
.Width
= Width
;
735 object
->currentDesc
.Height
= Height
;
736 object
->currentDesc
.MultiSampleType
= MultiSample
;
737 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
738 object
->glDescription
.level
= Level
;
742 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
743 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
744 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
747 if (WINED3DFMT_UNKNOWN
!= Format
) {
748 object
->bytesPerPixel
= tableEntry
->bpp
;
750 object
->bytesPerPixel
= 0;
753 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
755 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
757 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
758 * this function is too deep to need to care about things like this.
759 * Levels need to be checked too, and possibly Type since they all affect what can be done.
760 * ****************************************/
762 case WINED3DPOOL_SCRATCH
:
764 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
765 "which are mutually exclusive, setting lockable to TRUE\n");
768 case WINED3DPOOL_SYSTEMMEM
:
769 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
770 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
771 case WINED3DPOOL_MANAGED
:
772 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
773 "Usage of DYNAMIC which are mutually exclusive, not doing "
774 "anything just telling you.\n");
776 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
777 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
778 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
779 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
782 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
786 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
787 FIXME("Trying to create a render target that isn't in the default pool\n");
790 /* mark the texture as dirty so that it gets loaded first time around*/
791 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
792 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
793 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
794 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
796 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
797 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
798 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
800 /* Look at the implementation and set the correct Vtable */
803 /* Check if a 3D adapter is available when creating gl surfaces */
805 ERR("OpenGL surfaces are not available without opengl\n");
806 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
807 HeapFree(GetProcessHeap(), 0, object
);
808 return WINED3DERR_NOTAVAILABLE
;
813 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
817 /* To be sure to catch this */
818 ERR("Unknown requested surface implementation %d!\n", Impl
);
819 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
820 return WINED3DERR_INVALIDCALL
;
823 list_init(&object
->renderbuffers
);
825 /* Call the private setup routine */
826 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
830 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
831 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
832 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
833 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
835 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
836 IWineD3DTextureImpl
*object
;
841 unsigned int pow2Width
;
842 unsigned int pow2Height
;
843 const GlPixelFormatDesc
*glDesc
;
844 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
847 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
848 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
849 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
851 /* TODO: It should only be possible to create textures for formats
852 that are reported as supported */
853 if (WINED3DFMT_UNKNOWN
>= Format
) {
854 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
855 return WINED3DERR_INVALIDCALL
;
858 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
859 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
860 object
->width
= Width
;
861 object
->height
= Height
;
863 /** Non-power2 support **/
864 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
868 /* Find the nearest pow2 match */
869 pow2Width
= pow2Height
= 1;
870 while (pow2Width
< Width
) pow2Width
<<= 1;
871 while (pow2Height
< Height
) pow2Height
<<= 1;
874 /** FIXME: add support for real non-power-two if it's provided by the video card **/
875 /* Precalculated scaling for 'faked' non power of two texture coords */
876 object
->pow2scalingFactorX
= (((float)Width
) / ((float)pow2Width
));
877 object
->pow2scalingFactorY
= (((float)Height
) / ((float)pow2Height
));
878 TRACE(" xf(%f) yf(%f)\n", object
->pow2scalingFactorX
, object
->pow2scalingFactorY
);
880 /* Calculate levels for mip mapping */
881 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
882 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
883 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
884 return WINED3DERR_INVALIDCALL
;
887 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
888 return WINED3DERR_INVALIDCALL
;
890 object
->baseTexture
.levels
= 1;
891 } else if (Levels
== 0) {
892 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
893 object
->baseTexture
.levels
++;
896 while (tmpW
> 1 || tmpH
> 1) {
897 tmpW
= max(1, tmpW
>> 1);
898 tmpH
= max(1, tmpH
>> 1);
899 object
->baseTexture
.levels
++;
901 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
904 /* Generate all the surfaces */
907 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
909 /* use the callback to create the texture surface */
910 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
911 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
912 FIXME("Failed to create surface %p\n", object
);
914 object
->surfaces
[i
] = NULL
;
915 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
921 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
922 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
923 /* calculate the next mipmap level */
924 tmpW
= max(1, tmpW
>> 1);
925 tmpH
= max(1, tmpH
>> 1);
927 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
929 TRACE("(%p) : Created texture %p\n", This
, object
);
933 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
934 UINT Width
, UINT Height
, UINT Depth
,
935 UINT Levels
, DWORD Usage
,
936 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
937 IWineD3DVolumeTexture
**ppVolumeTexture
,
938 HANDLE
*pSharedHandle
, IUnknown
*parent
,
939 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
941 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
942 IWineD3DVolumeTextureImpl
*object
;
947 const GlPixelFormatDesc
*glDesc
;
948 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
950 /* TODO: It should only be possible to create textures for formats
951 that are reported as supported */
952 if (WINED3DFMT_UNKNOWN
>= Format
) {
953 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
954 return WINED3DERR_INVALIDCALL
;
957 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
958 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
960 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
961 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
963 object
->width
= Width
;
964 object
->height
= Height
;
965 object
->depth
= Depth
;
967 /* Calculate levels for mip mapping */
968 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
969 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
970 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
971 return WINED3DERR_INVALIDCALL
;
974 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
975 return WINED3DERR_INVALIDCALL
;
978 } else if (Levels
== 0) {
979 object
->baseTexture
.levels
++;
983 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
984 tmpW
= max(1, tmpW
>> 1);
985 tmpH
= max(1, tmpH
>> 1);
986 tmpD
= max(1, tmpD
>> 1);
987 object
->baseTexture
.levels
++;
989 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
992 /* Generate all the surfaces */
997 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1000 /* Create the volume */
1001 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
1002 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
1005 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
1006 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
1007 *ppVolumeTexture
= NULL
;
1011 /* Set its container to this object */
1012 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1014 /* calcualte the next mipmap level */
1015 tmpW
= max(1, tmpW
>> 1);
1016 tmpH
= max(1, tmpH
>> 1);
1017 tmpD
= max(1, tmpD
>> 1);
1019 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1021 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1022 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1026 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1027 UINT Width
, UINT Height
, UINT Depth
,
1029 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1030 IWineD3DVolume
** ppVolume
,
1031 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1033 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1034 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1035 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1037 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1039 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1040 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1042 object
->currentDesc
.Width
= Width
;
1043 object
->currentDesc
.Height
= Height
;
1044 object
->currentDesc
.Depth
= Depth
;
1045 object
->bytesPerPixel
= formatDesc
->bpp
;
1047 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1048 object
->lockable
= TRUE
;
1049 object
->locked
= FALSE
;
1050 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1051 object
->dirty
= TRUE
;
1053 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1056 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1057 UINT Levels
, DWORD Usage
,
1058 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1059 IWineD3DCubeTexture
**ppCubeTexture
,
1060 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1061 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1063 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1064 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1068 unsigned int pow2EdgeLength
= EdgeLength
;
1069 const GlPixelFormatDesc
*glDesc
;
1070 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1072 /* TODO: It should only be possible to create textures for formats
1073 that are reported as supported */
1074 if (WINED3DFMT_UNKNOWN
>= Format
) {
1075 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1076 return WINED3DERR_INVALIDCALL
;
1079 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1080 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1081 return WINED3DERR_INVALIDCALL
;
1084 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1085 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1087 TRACE("(%p) Create Cube Texture\n", This
);
1089 /** Non-power2 support **/
1091 /* Find the nearest pow2 match */
1093 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1095 object
->edgeLength
= EdgeLength
;
1096 /* TODO: support for native non-power 2 */
1097 /* Precalculated scaling for 'faked' non power of two texture coords */
1098 object
->pow2scalingFactor
= ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1100 /* Calculate levels for mip mapping */
1101 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1102 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1103 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1104 HeapFree(GetProcessHeap(), 0, object
);
1105 *ppCubeTexture
= NULL
;
1107 return WINED3DERR_INVALIDCALL
;
1110 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1111 HeapFree(GetProcessHeap(), 0, object
);
1112 *ppCubeTexture
= NULL
;
1114 return WINED3DERR_INVALIDCALL
;
1117 } else if (Levels
== 0) {
1118 object
->baseTexture
.levels
++;
1121 tmpW
= max(1, tmpW
>> 1);
1122 object
->baseTexture
.levels
++;
1124 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1127 /* Generate all the surfaces */
1129 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1131 /* Create the 6 faces */
1132 for (j
= 0; j
< 6; j
++) {
1134 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1135 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1137 if(hr
!= WINED3D_OK
) {
1141 for (l
= 0; l
< j
; l
++) {
1142 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1144 for (k
= 0; k
< i
; k
++) {
1145 for (l
= 0; l
< 6; l
++) {
1146 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1150 FIXME("(%p) Failed to create surface\n",object
);
1151 HeapFree(GetProcessHeap(),0,object
);
1152 *ppCubeTexture
= NULL
;
1155 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1156 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1158 tmpW
= max(1, tmpW
>> 1);
1160 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1162 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1163 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1167 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1168 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1169 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1170 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1172 /* Just a check to see if we support this type of query */
1174 case WINED3DQUERYTYPE_OCCLUSION
:
1175 TRACE("(%p) occlusion query\n", This
);
1176 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1179 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1182 case WINED3DQUERYTYPE_EVENT
:
1183 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1184 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1185 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1187 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1192 case WINED3DQUERYTYPE_VCACHE
:
1193 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1194 case WINED3DQUERYTYPE_VERTEXSTATS
:
1195 case WINED3DQUERYTYPE_TIMESTAMP
:
1196 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1197 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1198 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1199 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1200 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1201 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1202 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1203 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1205 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1207 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1211 D3DCREATEOBJECTINSTANCE(object
, Query
)
1212 object
->type
= Type
;
1213 /* allocated the 'extended' data based on the type of query requested */
1215 case WINED3DQUERYTYPE_OCCLUSION
:
1216 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1217 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1219 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1220 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1221 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1224 case WINED3DQUERYTYPE_EVENT
:
1225 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1226 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1228 if(GL_SUPPORT(APPLE_FENCE
)) {
1229 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1230 checkGLcall("glGenFencesAPPLE");
1231 } else if(GL_SUPPORT(NV_FENCE
)) {
1232 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1233 checkGLcall("glGenFencesNV");
1237 case WINED3DQUERYTYPE_VCACHE
:
1238 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1239 case WINED3DQUERYTYPE_VERTEXSTATS
:
1240 case WINED3DQUERYTYPE_TIMESTAMP
:
1241 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1242 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1243 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1244 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1245 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1246 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1247 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1248 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1250 object
->extendedData
= 0;
1251 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1253 TRACE("(%p) : Created Query %p\n", This
, object
);
1257 /*****************************************************************************
1258 * IWineD3DDeviceImpl_SetupFullscreenWindow
1260 * Helper function that modifies a HWND's Style and ExStyle for proper
1264 * iface: Pointer to the IWineD3DDevice interface
1265 * window: Window to setup
1267 *****************************************************************************/
1268 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1269 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1271 LONG style
, exStyle
;
1272 /* Don't do anything if an original style is stored.
1273 * That shouldn't happen
1275 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1276 if (This
->style
|| This
->exStyle
) {
1277 ERR("(%p): Want to change the window parameters of HWND %p, but "
1278 "another style is stored for restoration afterwards\n", This
, window
);
1281 /* Get the parameters and save them */
1282 style
= GetWindowLongW(window
, GWL_STYLE
);
1283 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1284 This
->style
= style
;
1285 This
->exStyle
= exStyle
;
1287 /* Filter out window decorations */
1288 style
&= ~WS_CAPTION
;
1289 style
&= ~WS_THICKFRAME
;
1290 exStyle
&= ~WS_EX_WINDOWEDGE
;
1291 exStyle
&= ~WS_EX_CLIENTEDGE
;
1293 /* Make sure the window is managed, otherwise we won't get keyboard input */
1294 style
|= WS_POPUP
| WS_SYSMENU
;
1296 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1297 This
->style
, This
->exStyle
, style
, exStyle
);
1299 SetWindowLongW(window
, GWL_STYLE
, style
);
1300 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1302 /* Inform the window about the update. */
1303 SetWindowPos(window
, HWND_TOP
, 0, 0,
1304 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1305 ShowWindow(window
, SW_NORMAL
);
1308 /*****************************************************************************
1309 * IWineD3DDeviceImpl_RestoreWindow
1311 * Helper function that restores a windows' properties when taking it out
1312 * of fullscreen mode
1315 * iface: Pointer to the IWineD3DDevice interface
1316 * window: Window to setup
1318 *****************************************************************************/
1319 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1320 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1322 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1323 * switch, do nothing
1325 if (!This
->style
&& !This
->exStyle
) return;
1327 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1328 This
, window
, This
->style
, This
->exStyle
);
1330 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1331 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1333 /* Delete the old values */
1337 /* Inform the window about the update */
1338 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1339 0, 0, 0, 0, /* Pos, Size, ignored */
1340 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1343 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1344 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1346 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1347 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1348 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1351 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1352 HRESULT hr
= WINED3D_OK
;
1353 IUnknown
*bufferParent
;
1355 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1357 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1358 * does a device hold a reference to a swap chain giving them a lifetime of the device
1359 * or does the swap chain notify the device of its destruction.
1360 *******************************/
1362 /* Check the params */
1363 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1364 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1365 return WINED3DERR_INVALIDCALL
;
1366 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1367 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");
1370 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1372 /*********************
1373 * Lookup the window Handle and the relating X window handle
1374 ********************/
1376 /* Setup hwnd we are using, plus which display this equates to */
1377 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1378 if (!object
->win_handle
) {
1379 object
->win_handle
= This
->createParms
.hFocusWindow
;
1382 hDc
= GetDC(object
->win_handle
);
1383 TRACE("Using hDc %p\n", hDc
);
1386 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1387 return WINED3DERR_NOTAVAILABLE
;
1390 object
->orig_width
= GetSystemMetrics(SM_CXSCREEN
);
1391 object
->orig_height
= GetSystemMetrics(SM_CYSCREEN
);
1392 object
->orig_fmt
= pixelformat_for_depth(GetDeviceCaps(hDc
, BITSPIXEL
) * GetDeviceCaps(hDc
, PLANES
));
1393 ReleaseDC(object
->win_handle
, hDc
);
1395 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1396 * then the corresponding dimension of the client area of the hDeviceWindow
1397 * (or the focus window, if hDeviceWindow is NULL) is taken.
1398 **********************/
1400 if (pPresentationParameters
->Windowed
&&
1401 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1402 (pPresentationParameters
->BackBufferHeight
== 0) ||
1403 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1406 GetClientRect(object
->win_handle
, &Rect
);
1408 if (pPresentationParameters
->BackBufferWidth
== 0) {
1409 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1410 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1412 if (pPresentationParameters
->BackBufferHeight
== 0) {
1413 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1414 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1416 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1417 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1418 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1422 /* Put the correct figures in the presentation parameters */
1423 TRACE("Copying across presentation parameters\n");
1424 object
->presentParms
= *pPresentationParameters
;
1426 TRACE("calling rendertarget CB\n");
1427 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1429 object
->presentParms
.BackBufferWidth
,
1430 object
->presentParms
.BackBufferHeight
,
1431 object
->presentParms
.BackBufferFormat
,
1432 object
->presentParms
.MultiSampleType
,
1433 object
->presentParms
.MultiSampleQuality
,
1434 TRUE
/* Lockable */,
1435 &object
->frontBuffer
,
1436 NULL
/* pShared (always null)*/);
1437 if (object
->frontBuffer
!= NULL
) {
1438 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1439 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1441 ERR("Failed to create the front buffer\n");
1446 * Create an opengl context for the display visual
1447 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1448 * use different properties after that point in time. FIXME: How to handle when requested format
1449 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1450 * it chooses is identical to the one already being used!
1451 **********************************/
1452 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1454 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1455 if(!object
->context
)
1456 return E_OUTOFMEMORY
;
1457 object
->num_contexts
= 1;
1459 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1460 if (!object
->context
[0]) {
1461 ERR("Failed to create a new context\n");
1462 hr
= WINED3DERR_NOTAVAILABLE
;
1465 TRACE("Context created (HWND=%p, glContext=%p)\n",
1466 object
->win_handle
, object
->context
[0]->glCtx
);
1469 /*********************
1470 * Windowed / Fullscreen
1471 *******************/
1474 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1475 * so we should really check to see if there is a fullscreen swapchain already
1476 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1477 **************************************/
1479 if (!pPresentationParameters
->Windowed
) {
1486 /* Get info on the current display setup */
1488 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1491 /* Change the display settings */
1492 memset(&devmode
, 0, sizeof(devmode
));
1493 devmode
.dmSize
= sizeof(devmode
);
1494 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1495 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1496 devmode
.dmPelsWidth
= pPresentationParameters
->BackBufferWidth
;
1497 devmode
.dmPelsHeight
= pPresentationParameters
->BackBufferHeight
;
1498 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1500 /* For GetDisplayMode */
1501 This
->ddraw_width
= devmode
.dmPelsWidth
;
1502 This
->ddraw_height
= devmode
.dmPelsHeight
;
1503 This
->ddraw_format
= pPresentationParameters
->BackBufferFormat
;
1505 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1507 /* And finally clip mouse to our screen */
1508 SetRect(&clip_rc
, 0, 0, devmode
.dmPelsWidth
, devmode
.dmPelsHeight
);
1509 ClipCursor(&clip_rc
);
1512 /*********************
1513 * Create the back, front and stencil buffers
1514 *******************/
1515 if(object
->presentParms
.BackBufferCount
> 0) {
1518 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1519 if(!object
->backBuffer
) {
1520 ERR("Out of memory\n");
1525 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1526 TRACE("calling rendertarget CB\n");
1527 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1529 object
->presentParms
.BackBufferWidth
,
1530 object
->presentParms
.BackBufferHeight
,
1531 object
->presentParms
.BackBufferFormat
,
1532 object
->presentParms
.MultiSampleType
,
1533 object
->presentParms
.MultiSampleQuality
,
1534 TRUE
/* Lockable */,
1535 &object
->backBuffer
[i
],
1536 NULL
/* pShared (always null)*/);
1537 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1538 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1540 ERR("Cannot create new back buffer\n");
1544 glDrawBuffer(GL_BACK
);
1545 checkGLcall("glDrawBuffer(GL_BACK)");
1549 object
->backBuffer
= NULL
;
1551 /* Single buffering - draw to front buffer */
1553 glDrawBuffer(GL_FRONT
);
1554 checkGLcall("glDrawBuffer(GL_FRONT)");
1558 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1559 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1560 TRACE("Creating depth stencil buffer\n");
1561 if (This
->depthStencilBuffer
== NULL
) {
1562 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1564 object
->presentParms
.BackBufferWidth
,
1565 object
->presentParms
.BackBufferHeight
,
1566 object
->presentParms
.AutoDepthStencilFormat
,
1567 object
->presentParms
.MultiSampleType
,
1568 object
->presentParms
.MultiSampleQuality
,
1569 FALSE
/* FIXME: Discard */,
1570 &This
->depthStencilBuffer
,
1571 NULL
/* pShared (always null)*/ );
1572 if (This
->depthStencilBuffer
!= NULL
)
1573 IWineD3DSurface_SetContainer(This
->depthStencilBuffer
, 0);
1576 /** TODO: A check on width, height and multisample types
1577 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1578 ****************************/
1579 object
->wantsDepthStencilBuffer
= TRUE
;
1581 object
->wantsDepthStencilBuffer
= FALSE
;
1584 TRACE("Created swapchain %p\n", object
);
1585 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1589 if (object
->backBuffer
) {
1591 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1592 if(object
->backBuffer
[i
]) {
1593 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1594 IUnknown_Release(bufferParent
); /* once for the get parent */
1595 if (IUnknown_Release(bufferParent
) > 0) {
1596 FIXME("(%p) Something's still holding the back buffer\n",This
);
1600 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1601 object
->backBuffer
= NULL
;
1603 if(object
->context
[0])
1604 DestroyContext(This
, object
->context
[0]);
1605 if(object
->frontBuffer
) {
1606 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1607 IUnknown_Release(bufferParent
); /* once for the get parent */
1608 if (IUnknown_Release(bufferParent
) > 0) {
1609 FIXME("(%p) Something's still holding the front buffer\n",This
);
1612 HeapFree(GetProcessHeap(), 0, object
);
1616 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1617 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1618 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1619 TRACE("(%p)\n", This
);
1621 return This
->NumberOfSwapChains
;
1624 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1625 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1626 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1628 if(iSwapChain
< This
->NumberOfSwapChains
) {
1629 *pSwapChain
= This
->swapchains
[iSwapChain
];
1630 IWineD3DSwapChain_AddRef(*pSwapChain
);
1631 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1634 TRACE("Swapchain out of range\n");
1636 return WINED3DERR_INVALIDCALL
;
1641 * Vertex Declaration
1643 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1644 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, size_t element_count
) {
1645 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1646 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1647 HRESULT hr
= WINED3D_OK
;
1649 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1650 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1652 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1654 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1659 static size_t ConvertFvfToDeclaration(DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1661 unsigned int idx
, idx2
;
1662 unsigned int offset
;
1663 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1664 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1665 BOOL has_blend_idx
= has_blend
&&
1666 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1667 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1668 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1669 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1670 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1671 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1672 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1674 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1675 DWORD texcoords
= (fvf
& 0x00FF0000) >> 16;
1677 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1678 WINED3DVERTEXELEMENT
*elements
= NULL
;
1681 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1682 if (has_blend_idx
) num_blends
--;
1684 /* Compute declaration size */
1685 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1686 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1688 /* convert the declaration */
1689 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1693 memcpy(&elements
[size
-1], &end_element
, sizeof(WINED3DVERTEXELEMENT
));
1696 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1697 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1698 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1701 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1702 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1704 elements
[idx
].UsageIndex
= 0;
1707 if (has_blend
&& (num_blends
> 0)) {
1708 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1709 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1711 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1712 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1713 elements
[idx
].UsageIndex
= 0;
1716 if (has_blend_idx
) {
1717 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1718 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1719 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1720 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1721 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1723 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1724 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1725 elements
[idx
].UsageIndex
= 0;
1729 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1730 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1731 elements
[idx
].UsageIndex
= 0;
1735 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1736 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1737 elements
[idx
].UsageIndex
= 0;
1741 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1742 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1743 elements
[idx
].UsageIndex
= 0;
1747 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1748 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1749 elements
[idx
].UsageIndex
= 1;
1752 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1753 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1754 switch (numcoords
) {
1755 case WINED3DFVF_TEXTUREFORMAT1
:
1756 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1758 case WINED3DFVF_TEXTUREFORMAT2
:
1759 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1761 case WINED3DFVF_TEXTUREFORMAT3
:
1762 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1764 case WINED3DFVF_TEXTUREFORMAT4
:
1765 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1768 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1769 elements
[idx
].UsageIndex
= idx2
;
1773 /* Now compute offsets, and initialize the rest of the fields */
1774 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1775 elements
[idx
].Stream
= 0;
1776 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1777 elements
[idx
].Offset
= offset
;
1778 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1781 *ppVertexElements
= elements
;
1785 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1786 WINED3DVERTEXELEMENT
* elements
= NULL
;
1790 size
= ConvertFvfToDeclaration(Fvf
, &elements
);
1791 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1793 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1794 HeapFree(GetProcessHeap(), 0, elements
);
1795 if (hr
!= S_OK
) return hr
;
1800 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1801 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1802 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1803 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1804 HRESULT hr
= WINED3D_OK
;
1805 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1806 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1808 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1810 if (vertex_declaration
) {
1811 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1814 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1816 if (WINED3D_OK
!= hr
) {
1817 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1818 IWineD3DVertexShader_Release(*ppVertexShader
);
1819 return WINED3DERR_INVALIDCALL
;
1825 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1826 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1827 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1828 HRESULT hr
= WINED3D_OK
;
1830 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1831 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1832 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1833 if (WINED3D_OK
== hr
) {
1834 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1836 WARN("(%p) : Failed to create pixel shader\n", This
);
1842 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1843 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1844 IWineD3DPaletteImpl
*object
;
1846 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1848 /* Create the new object */
1849 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1851 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1852 return E_OUTOFMEMORY
;
1855 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1857 object
->Flags
= Flags
;
1858 object
->parent
= Parent
;
1859 object
->wineD3DDevice
= This
;
1860 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1862 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1865 HeapFree( GetProcessHeap(), 0, object
);
1866 return E_OUTOFMEMORY
;
1869 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1871 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1875 *Palette
= (IWineD3DPalette
*) object
;
1880 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1884 HDC dcb
= NULL
, dcs
= NULL
;
1885 WINEDDCOLORKEY colorkey
;
1887 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1890 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1891 dcb
= CreateCompatibleDC(NULL
);
1893 SelectObject(dcb
, hbm
);
1897 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1898 * couldn't be loaded
1900 memset(&bm
, 0, sizeof(bm
));
1905 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1906 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1907 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1909 ERR("Wine logo requested, but failed to create surface\n");
1914 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1915 if(FAILED(hr
)) goto out
;
1916 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1917 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1919 colorkey
.dwColorSpaceLowValue
= 0;
1920 colorkey
.dwColorSpaceHighValue
= 0;
1921 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1923 /* Fill the surface with a white color to show that wined3d is there */
1924 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1937 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
1938 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1939 IWineD3DSwapChainImpl
*swapchain
;
1943 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
1944 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1946 /* TODO: Test if OpenGL is compiled in and loaded */
1948 TRACE("(%p) : Creating stateblock\n", This
);
1949 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1950 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1952 (IWineD3DStateBlock
**)&This
->stateBlock
,
1954 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1955 WARN("Failed to create stateblock\n");
1958 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1959 This
->updateStateBlock
= This
->stateBlock
;
1960 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1962 hr
= allocate_shader_constants(This
->updateStateBlock
);
1963 if (WINED3D_OK
!= hr
) {
1967 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
1968 This
->fbo_color_attachments
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
1969 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
1971 /* Initialize the texture unit mapping to a 1:1 mapping */
1972 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
1973 if (state
< GL_LIMITS(fragment_samplers
)) {
1974 This
->texUnitMap
[state
] = state
;
1975 This
->rev_tex_unit_map
[state
] = state
;
1977 This
->texUnitMap
[state
] = -1;
1978 This
->rev_tex_unit_map
[state
] = -1;
1982 /* Setup the implicit swapchain */
1983 TRACE("Creating implicit swapchain\n");
1984 hr
=D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1985 if (FAILED(hr
) || !swapchain
) {
1986 WARN("Failed to create implicit swapchain\n");
1990 This
->NumberOfSwapChains
= 1;
1991 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1992 if(!This
->swapchains
) {
1993 ERR("Out of memory!\n");
1996 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1998 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, swapchain
->win_handle
);
2000 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2001 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2002 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2003 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2006 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2007 This
->render_targets
[0] = swapchain
->frontBuffer
;
2008 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2010 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2011 This
->activeContext
= swapchain
->context
[0];
2012 This
->lastThread
= GetCurrentThreadId();
2014 /* Depth Stencil support */
2015 This
->stencilBufferTarget
= This
->depthStencilBuffer
;
2016 if (NULL
!= This
->stencilBufferTarget
) {
2017 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2020 /* Set up some starting GL setup */
2023 /* Setup all the devices defaults */
2024 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2026 IWineD3DImpl_CheckGraphicsMemory();
2029 { /* Set a default viewport */
2033 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2034 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2037 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2040 /* Initialize the current view state */
2041 This
->view_ident
= 1;
2042 This
->contexts
[0]->last_was_rhw
= 0;
2043 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2044 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2046 switch(wined3d_settings
.offscreen_rendering_mode
) {
2049 This
->offscreenBuffer
= GL_BACK
;
2052 case ORM_BACKBUFFER
:
2054 if(GL_LIMITS(aux_buffers
) > 0) {
2055 TRACE("Using auxilliary buffer for offscreen rendering\n");
2056 This
->offscreenBuffer
= GL_AUX0
;
2058 TRACE("Using back buffer for offscreen rendering\n");
2059 This
->offscreenBuffer
= GL_BACK
;
2064 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2067 /* Clear the screen */
2068 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2069 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2072 This
->d3d_initialized
= TRUE
;
2074 if(wined3d_settings
.logo
) {
2075 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2080 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2081 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2082 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2083 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2084 This
->NumberOfSwapChains
= 0;
2086 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2088 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2089 if(This
->stateBlock
) {
2090 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2091 This
->stateBlock
= NULL
;
2096 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2097 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2100 TRACE("(%p)\n", This
);
2102 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2104 /* I don't think that the interface guarants that the device is destroyed from the same thread
2105 * it was created. Thus make sure a context is active for the glDelete* calls
2107 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2109 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2111 TRACE("Deleting high order patches\n");
2112 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2113 struct list
*e1
, *e2
;
2114 struct WineD3DRectPatch
*patch
;
2115 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2116 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2117 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2121 /* Delete the palette conversion shader if it is around */
2122 if(This
->paletteConversionShader
) {
2123 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2126 /* Delete the pbuffer context if there is any */
2127 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2129 /* Delete the mouse cursor texture */
2130 if(This
->cursorTexture
) {
2132 glDeleteTextures(1, &This
->cursorTexture
);
2134 This
->cursorTexture
= 0;
2137 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2138 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2140 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2141 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2144 /* Release the update stateblock */
2145 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2146 if(This
->updateStateBlock
!= This
->stateBlock
)
2147 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2149 This
->updateStateBlock
= NULL
;
2151 { /* because were not doing proper internal refcounts releasing the primary state block
2152 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2153 to set this->stateBlock = NULL; first */
2154 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2155 This
->stateBlock
= NULL
;
2157 /* Release the stateblock */
2158 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2159 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2163 /* Release the buffers (with sanity checks)*/
2164 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2165 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2166 if(This
->depthStencilBuffer
!= This
->stencilBufferTarget
)
2167 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This
);
2169 This
->stencilBufferTarget
= NULL
;
2171 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2172 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2173 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2175 TRACE("Setting rendertarget to NULL\n");
2176 This
->render_targets
[0] = NULL
;
2178 if (This
->depthStencilBuffer
) {
2179 if(D3DCB_DestroyDepthStencilSurface(This
->depthStencilBuffer
) > 0) {
2180 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This
);
2182 This
->depthStencilBuffer
= NULL
;
2185 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2186 TRACE("Releasing the implicit swapchain %d\n", i
);
2187 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2188 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2192 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2193 This
->swapchains
= NULL
;
2194 This
->NumberOfSwapChains
= 0;
2196 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2197 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2198 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2199 This
->render_targets
= NULL
;
2200 This
->fbo_color_attachments
= NULL
;
2201 This
->draw_buffers
= NULL
;
2204 This
->d3d_initialized
= FALSE
;
2208 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2209 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2210 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2212 /* Setup the window for fullscreen mode */
2213 if(fullscreen
&& !This
->ddraw_fullscreen
) {
2214 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
2215 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
2216 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
2219 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2220 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2221 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2224 This
->ddraw_fullscreen
= fullscreen
;
2227 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2228 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2229 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2231 * There is no way to deactivate thread safety once it is enabled.
2233 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2234 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2236 /*For now just store the flag(needed in case of ddraw) */
2237 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2242 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2244 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2246 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2249 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2251 /* Resize the screen even without a window:
2252 * The app could have unset it with SetCooperativeLevel, but not called
2253 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2254 * but we don't have any hwnd
2257 memset(&devmode
, 0, sizeof(devmode
));
2258 devmode
.dmSize
= sizeof(devmode
);
2259 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2260 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2261 if(devmode
.dmBitsPerPel
== 24) devmode
.dmBitsPerPel
= 32;
2262 devmode
.dmPelsWidth
= pMode
->Width
;
2263 devmode
.dmPelsHeight
= pMode
->Height
;
2265 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2266 if (pMode
->RefreshRate
!= 0) {
2267 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2270 /* Only change the mode if necessary */
2271 if( (This
->ddraw_width
== pMode
->Width
) &&
2272 (This
->ddraw_height
== pMode
->Height
) &&
2273 (This
->ddraw_format
== pMode
->Format
) &&
2274 (pMode
->RefreshRate
== 0) ) {
2278 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2279 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2280 if(devmode
.dmDisplayFrequency
!= 0) {
2281 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2282 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2283 devmode
.dmDisplayFrequency
= 0;
2284 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2286 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2287 return WINED3DERR_NOTAVAILABLE
;
2291 /* Store the new values */
2292 This
->ddraw_width
= pMode
->Width
;
2293 This
->ddraw_height
= pMode
->Height
;
2294 This
->ddraw_format
= pMode
->Format
;
2296 /* Only do this with a window of course */
2297 if(This
->ddraw_window
)
2298 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2300 /* And finally clip mouse to our screen */
2301 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2302 ClipCursor(&clip_rc
);
2307 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2308 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2309 *ppD3D
= This
->wineD3D
;
2310 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2311 IWineD3D_AddRef(*ppD3D
);
2315 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2316 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2318 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2319 (This
->adapter
->TextureRam
/(1024*1024)),
2320 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2321 /* return simulated texture memory left */
2322 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2330 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2333 /* Update the current state block */
2334 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2336 if(This
->updateStateBlock
->fvf
== fvf
) {
2337 TRACE("Application is setting the old fvf over, nothing to do\n");
2341 This
->updateStateBlock
->fvf
= fvf
;
2342 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2343 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2348 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2349 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2350 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2351 *pfvf
= This
->stateBlock
->fvf
;
2356 * Get / Set Stream Source
2358 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2360 IWineD3DVertexBuffer
*oldSrc
;
2362 if (StreamNumber
>= MAX_STREAMS
) {
2363 WARN("Stream out of range %d\n", StreamNumber
);
2364 return WINED3DERR_INVALIDCALL
;
2367 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2368 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2370 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2372 if(oldSrc
== pStreamData
&&
2373 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2374 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2375 TRACE("Application is setting the old values over, nothing to do\n");
2379 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2381 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2382 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2385 /* Handle recording of state blocks */
2386 if (This
->isRecordingState
) {
2387 TRACE("Recording... not performing anything\n");
2388 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2389 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2393 /* Need to do a getParent and pass the reffs up */
2394 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2395 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2396 so for now, just count internally */
2397 if (pStreamData
!= NULL
) {
2398 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2399 InterlockedIncrement(&vbImpl
->bindCount
);
2400 IWineD3DVertexBuffer_AddRef(pStreamData
);
2402 if (oldSrc
!= NULL
) {
2403 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2404 IWineD3DVertexBuffer_Release(oldSrc
);
2407 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2412 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2413 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2415 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2416 This
->stateBlock
->streamSource
[StreamNumber
],
2417 This
->stateBlock
->streamOffset
[StreamNumber
],
2418 This
->stateBlock
->streamStride
[StreamNumber
]);
2420 if (StreamNumber
>= MAX_STREAMS
) {
2421 WARN("Stream out of range %d\n", StreamNumber
);
2422 return WINED3DERR_INVALIDCALL
;
2424 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2425 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2427 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2430 if (*pStream
!= NULL
) {
2431 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2436 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2437 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2438 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2439 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2441 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2442 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2444 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2445 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2447 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2448 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2449 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2455 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2456 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2458 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2459 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2461 TRACE("(%p) : returning %d\n", This
, *Divider
);
2467 * Get / Set & Multiply Transform
2469 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2472 /* Most of this routine, comments included copied from ddraw tree initially: */
2473 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2475 /* Handle recording of state blocks */
2476 if (This
->isRecordingState
) {
2477 TRACE("Recording... not performing anything\n");
2478 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2479 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2484 * If the new matrix is the same as the current one,
2485 * we cut off any further processing. this seems to be a reasonable
2486 * optimization because as was noticed, some apps (warcraft3 for example)
2487 * tend towards setting the same matrix repeatedly for some reason.
2489 * From here on we assume that the new matrix is different, wherever it matters.
2491 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2492 TRACE("The app is setting the same matrix over again\n");
2495 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2499 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2500 where ViewMat = Camera space, WorldMat = world space.
2502 In OpenGL, camera and world space is combined into GL_MODELVIEW
2503 matrix. The Projection matrix stay projection matrix.
2506 /* Capture the times we can just ignore the change for now */
2507 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2508 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2509 /* Handled by the state manager */
2512 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2516 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2517 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2518 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2519 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2523 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2524 WINED3DMATRIX
*mat
= NULL
;
2527 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2528 * below means it will be recorded in a state block change, but it
2529 * works regardless where it is recorded.
2530 * If this is found to be wrong, change to StateBlock.
2532 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2533 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2535 if (State
< HIGHEST_TRANSFORMSTATE
)
2537 mat
= &This
->updateStateBlock
->transforms
[State
];
2539 FIXME("Unhandled transform state!!\n");
2542 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2544 /* Apply change via set transform - will reapply to eg. lights this way */
2545 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2551 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2552 you can reference any indexes you want as long as that number max are enabled at any
2553 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2554 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2555 but when recording, just build a chain pretty much of commands to be replayed. */
2557 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2559 PLIGHTINFOEL
*object
= NULL
;
2560 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2563 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2564 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2566 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2570 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2571 return WINED3DERR_INVALIDCALL
;
2574 switch(pLight
->Type
) {
2575 case WINED3DLIGHT_POINT
:
2576 case WINED3DLIGHT_SPOT
:
2577 case WINED3DLIGHT_PARALLELPOINT
:
2578 case WINED3DLIGHT_GLSPOT
:
2579 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2582 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2583 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2584 return WINED3DERR_INVALIDCALL
;
2588 case WINED3DLIGHT_DIRECTIONAL
:
2589 /* Ignores attenuation */
2593 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2594 return WINED3DERR_INVALIDCALL
;
2597 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2598 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2599 if(object
->OriginalIndex
== Index
) break;
2604 TRACE("Adding new light\n");
2605 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2607 ERR("Out of memory error when allocating a light\n");
2608 return E_OUTOFMEMORY
;
2610 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2611 object
->glIndex
= -1;
2612 object
->OriginalIndex
= Index
;
2613 object
->changed
= TRUE
;
2616 /* Initialize the object */
2617 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
,
2618 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2619 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2620 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2621 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2622 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2623 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2625 /* Save away the information */
2626 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2628 switch (pLight
->Type
) {
2629 case WINED3DLIGHT_POINT
:
2631 object
->lightPosn
[0] = pLight
->Position
.x
;
2632 object
->lightPosn
[1] = pLight
->Position
.y
;
2633 object
->lightPosn
[2] = pLight
->Position
.z
;
2634 object
->lightPosn
[3] = 1.0f
;
2635 object
->cutoff
= 180.0f
;
2639 case WINED3DLIGHT_DIRECTIONAL
:
2641 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2642 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2643 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2644 object
->lightPosn
[3] = 0.0;
2645 object
->exponent
= 0.0f
;
2646 object
->cutoff
= 180.0f
;
2649 case WINED3DLIGHT_SPOT
:
2651 object
->lightPosn
[0] = pLight
->Position
.x
;
2652 object
->lightPosn
[1] = pLight
->Position
.y
;
2653 object
->lightPosn
[2] = pLight
->Position
.z
;
2654 object
->lightPosn
[3] = 1.0;
2657 object
->lightDirn
[0] = pLight
->Direction
.x
;
2658 object
->lightDirn
[1] = pLight
->Direction
.y
;
2659 object
->lightDirn
[2] = pLight
->Direction
.z
;
2660 object
->lightDirn
[3] = 1.0;
2663 * opengl-ish and d3d-ish spot lights use too different models for the
2664 * light "intensity" as a function of the angle towards the main light direction,
2665 * so we only can approximate very roughly.
2666 * however spot lights are rather rarely used in games (if ever used at all).
2667 * furthermore if still used, probably nobody pays attention to such details.
2669 if (pLight
->Falloff
== 0) {
2670 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2671 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2672 * will always be 1.0 for both of them, and we don't have to care for the
2673 * rest of the rather complex calculation
2675 object
->exponent
= 0;
2677 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2678 if (rho
< 0.0001) rho
= 0.0001f
;
2679 object
->exponent
= -0.3/log(cos(rho
/2));
2681 if (object
->exponent
> 128.0) {
2682 object
->exponent
= 128.0;
2684 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2690 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2693 /* Update the live definitions if the light is currently assigned a glIndex */
2694 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2695 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2700 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2701 PLIGHTINFOEL
*lightInfo
= NULL
;
2702 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2703 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2705 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2707 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2708 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2709 if(lightInfo
->OriginalIndex
== Index
) break;
2713 if (lightInfo
== NULL
) {
2714 TRACE("Light information requested but light not defined\n");
2715 return WINED3DERR_INVALIDCALL
;
2718 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2723 * Get / Set Light Enable
2724 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2726 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2727 PLIGHTINFOEL
*lightInfo
= NULL
;
2728 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2729 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2731 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2733 /* Tests show true = 128...not clear why */
2734 Enable
= Enable
? 128: 0;
2736 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2737 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2738 if(lightInfo
->OriginalIndex
== Index
) break;
2741 TRACE("Found light: %p\n", lightInfo
);
2743 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2744 if (lightInfo
== NULL
) {
2746 TRACE("Light enabled requested but light not defined, so defining one!\n");
2747 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2749 /* Search for it again! Should be fairly quick as near head of list */
2750 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2751 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2752 if(lightInfo
->OriginalIndex
== Index
) break;
2755 if (lightInfo
== NULL
) {
2756 FIXME("Adding default lights has failed dismally\n");
2757 return WINED3DERR_INVALIDCALL
;
2761 lightInfo
->enabledChanged
= TRUE
;
2763 if(lightInfo
->glIndex
!= -1) {
2764 if(!This
->isRecordingState
) {
2765 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2768 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2769 lightInfo
->glIndex
= -1;
2771 TRACE("Light already disabled, nothing to do\n");
2774 if (lightInfo
->glIndex
!= -1) {
2776 TRACE("Nothing to do as light was enabled\n");
2779 /* Find a free gl light */
2780 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2781 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2782 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2783 lightInfo
->glIndex
= i
;
2787 if(lightInfo
->glIndex
== -1) {
2788 ERR("Too many concurrently active lights\n");
2789 return WINED3DERR_INVALIDCALL
;
2792 /* i == lightInfo->glIndex */
2793 if(!This
->isRecordingState
) {
2794 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2802 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2804 PLIGHTINFOEL
*lightInfo
= NULL
;
2805 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2807 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2808 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2810 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2811 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2812 if(lightInfo
->OriginalIndex
== Index
) break;
2816 if (lightInfo
== NULL
) {
2817 TRACE("Light enabled state requested but light not defined\n");
2818 return WINED3DERR_INVALIDCALL
;
2820 /* true is 128 according to SetLightEnable */
2821 *pEnable
= lightInfo
->glIndex
!= -1 ? 128 : 0;
2826 * Get / Set Clip Planes
2828 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2829 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2830 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2832 /* Validate Index */
2833 if (Index
>= GL_LIMITS(clipplanes
)) {
2834 TRACE("Application has requested clipplane this device doesn't support\n");
2835 return WINED3DERR_INVALIDCALL
;
2838 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2840 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2841 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2842 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2843 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2844 TRACE("Application is setting old values over, nothing to do\n");
2848 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2849 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2850 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2851 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2853 /* Handle recording of state blocks */
2854 if (This
->isRecordingState
) {
2855 TRACE("Recording... not performing anything\n");
2859 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2864 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2865 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2866 TRACE("(%p) : for idx %d\n", This
, Index
);
2868 /* Validate Index */
2869 if (Index
>= GL_LIMITS(clipplanes
)) {
2870 TRACE("Application has requested clipplane this device doesn't support\n");
2871 return WINED3DERR_INVALIDCALL
;
2874 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2875 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2876 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2877 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2882 * Get / Set Clip Plane Status
2883 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2885 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2886 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2887 FIXME("(%p) : stub\n", This
);
2888 if (NULL
== pClipStatus
) {
2889 return WINED3DERR_INVALIDCALL
;
2891 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2892 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2896 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2897 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2898 FIXME("(%p) : stub\n", This
);
2899 if (NULL
== pClipStatus
) {
2900 return WINED3DERR_INVALIDCALL
;
2902 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2903 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2908 * Get / Set Material
2910 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2911 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2913 This
->updateStateBlock
->changed
.material
= TRUE
;
2914 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2916 /* Handle recording of state blocks */
2917 if (This
->isRecordingState
) {
2918 TRACE("Recording... not performing anything\n");
2922 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2926 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2927 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2928 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
2929 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2930 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2931 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2932 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2933 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2934 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2935 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2936 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2937 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2945 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
2946 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2947 IWineD3DIndexBuffer
*oldIdxs
;
2949 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2950 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2952 This
->updateStateBlock
->changed
.indices
= TRUE
;
2953 This
->updateStateBlock
->pIndexData
= pIndexData
;
2955 /* Handle recording of state blocks */
2956 if (This
->isRecordingState
) {
2957 TRACE("Recording... not performing anything\n");
2958 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
2959 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
2963 if(oldIdxs
!= pIndexData
) {
2964 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2965 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
2966 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
2971 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
2972 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2974 *ppIndexData
= This
->stateBlock
->pIndexData
;
2976 /* up ref count on ppindexdata */
2978 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
2979 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2981 TRACE("(%p) No index data set\n", This
);
2983 TRACE("Returning %p\n", *ppIndexData
);
2988 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2989 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2990 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2991 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2993 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2994 TRACE("Application is setting the old value over, nothing to do\n");
2998 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3000 if (This
->isRecordingState
) {
3001 TRACE("Recording... not performing anything\n");
3004 /* The base vertex index affects the stream sources */
3005 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3009 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3010 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3011 TRACE("(%p) : base_index %p\n", This
, base_index
);
3013 *base_index
= This
->stateBlock
->baseVertexIndex
;
3015 TRACE("Returning %u\n", *base_index
);
3021 * Get / Set Viewports
3023 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3024 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3026 TRACE("(%p)\n", This
);
3027 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3028 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
3030 /* Handle recording of state blocks */
3031 if (This
->isRecordingState
) {
3032 TRACE("Recording... not performing anything\n");
3036 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3037 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3039 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3044 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3045 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3046 TRACE("(%p)\n", This
);
3047 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
3052 * Get / Set Render States
3053 * TODO: Verify against dx9 definitions
3055 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3057 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3058 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3060 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3062 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3063 This
->updateStateBlock
->renderState
[State
] = Value
;
3065 /* Handle recording of state blocks */
3066 if (This
->isRecordingState
) {
3067 TRACE("Recording... not performing anything\n");
3071 /* Compared here and not before the assignment to allow proper stateblock recording */
3072 if(Value
== oldValue
) {
3073 TRACE("Application is setting the old value over, nothing to do\n");
3075 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3081 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3082 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3083 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3084 *pValue
= This
->stateBlock
->renderState
[State
];
3089 * Get / Set Sampler States
3090 * TODO: Verify against dx9 definitions
3093 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3094 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3097 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3098 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3100 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3101 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3105 * SetSampler is designed to allow for more than the standard up to 8 textures
3106 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3107 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3109 * http://developer.nvidia.com/object/General_FAQ.html#t6
3111 * There are two new settings for GForce
3113 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3114 * and the texture one:
3115 * GL_MAX_TEXTURE_COORDS_ARB.
3116 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3119 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3120 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3121 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3123 /* Handle recording of state blocks */
3124 if (This
->isRecordingState
) {
3125 TRACE("Recording... not performing anything\n");
3129 if(oldValue
== Value
) {
3130 TRACE("Application is setting the old value over, nothing to do\n");
3134 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3139 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3140 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3142 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3143 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3145 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3146 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3149 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3150 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3155 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3156 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3158 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3159 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3160 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3163 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3165 if(This
->isRecordingState
) {
3166 TRACE("Recording... not performing anything\n");
3170 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3175 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3176 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3178 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
3179 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3183 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3184 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3185 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3187 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3189 This
->updateStateBlock
->vertexDecl
= pDecl
;
3190 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3192 if (This
->isRecordingState
) {
3193 TRACE("Recording... not performing anything\n");
3195 } else if(pDecl
== oldDecl
) {
3196 /* Checked after the assignment to allow proper stateblock recording */
3197 TRACE("Application is setting the old declaration over, nothing to do\n");
3201 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3205 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3206 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3208 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3210 *ppDecl
= This
->stateBlock
->vertexDecl
;
3211 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3215 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3216 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3217 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3219 This
->updateStateBlock
->vertexShader
= pShader
;
3220 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3222 if (This
->isRecordingState
) {
3223 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3224 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3225 TRACE("Recording... not performing anything\n");
3227 } else if(oldShader
== pShader
) {
3228 /* Checked here to allow proper stateblock recording */
3229 TRACE("App is setting the old shader over, nothing to do\n");
3233 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3234 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3235 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3237 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3242 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3243 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3245 if (NULL
== ppShader
) {
3246 return WINED3DERR_INVALIDCALL
;
3248 *ppShader
= This
->stateBlock
->vertexShader
;
3249 if( NULL
!= *ppShader
)
3250 IWineD3DVertexShader_AddRef(*ppShader
);
3252 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3256 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3257 IWineD3DDevice
*iface
,
3259 CONST BOOL
*srcData
,
3262 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3263 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3265 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3266 iface
, srcData
, start
, count
);
3268 if (srcData
== NULL
|| cnt
< 0)
3269 return WINED3DERR_INVALIDCALL
;
3271 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3272 for (i
= 0; i
< cnt
; i
++)
3273 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3275 for (i
= start
; i
< cnt
+ start
; ++i
) {
3276 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3279 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3284 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3285 IWineD3DDevice
*iface
,
3290 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3291 int cnt
= min(count
, MAX_CONST_B
- start
);
3293 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3294 iface
, dstData
, start
, count
);
3296 if (dstData
== NULL
|| cnt
< 0)
3297 return WINED3DERR_INVALIDCALL
;
3299 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3303 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3304 IWineD3DDevice
*iface
,
3309 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3310 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3312 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3313 iface
, srcData
, start
, count
);
3315 if (srcData
== NULL
|| cnt
< 0)
3316 return WINED3DERR_INVALIDCALL
;
3318 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3319 for (i
= 0; i
< cnt
; i
++)
3320 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3321 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3323 for (i
= start
; i
< cnt
+ start
; ++i
) {
3324 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3327 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3332 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3333 IWineD3DDevice
*iface
,
3338 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3339 int cnt
= min(count
, MAX_CONST_I
- start
);
3341 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3342 iface
, dstData
, start
, count
);
3344 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3345 return WINED3DERR_INVALIDCALL
;
3347 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3351 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3352 IWineD3DDevice
*iface
,
3354 CONST
float *srcData
,
3357 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3360 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3361 iface
, srcData
, start
, count
);
3363 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3364 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3365 return WINED3DERR_INVALIDCALL
;
3367 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3369 for (i
= 0; i
< count
; i
++)
3370 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3371 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3374 for (i
= start
; i
< count
+ start
; ++i
) {
3375 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3376 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3377 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3378 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3379 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3381 ptr
->idx
[ptr
->count
++] = i
;
3382 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3386 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3391 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3392 IWineD3DDevice
*iface
,
3397 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3398 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3400 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3401 iface
, dstData
, start
, count
);
3403 if (dstData
== NULL
|| cnt
< 0)
3404 return WINED3DERR_INVALIDCALL
;
3406 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3410 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3412 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3413 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3417 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3418 int i
= This
->rev_tex_unit_map
[unit
];
3419 int j
= This
->texUnitMap
[stage
];
3421 This
->texUnitMap
[stage
] = unit
;
3422 if (i
!= -1 && i
!= stage
) {
3423 This
->texUnitMap
[i
] = -1;
3426 This
->rev_tex_unit_map
[unit
] = stage
;
3427 if (j
!= -1 && j
!= unit
) {
3428 This
->rev_tex_unit_map
[j
] = -1;
3432 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3435 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3436 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3437 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3438 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3439 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3440 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3441 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3442 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3443 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3445 if (color_op
== WINED3DTOP_DISABLE
) {
3446 /* Not used, and disable higher stages */
3447 while (i
< MAX_TEXTURES
) {
3448 This
->fixed_function_usage_map
[i
] = FALSE
;
3454 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3455 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3456 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3457 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3458 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3459 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3460 This
->fixed_function_usage_map
[i
] = TRUE
;
3462 This
->fixed_function_usage_map
[i
] = FALSE
;
3465 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3466 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3471 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3474 device_update_fixed_function_usage_map(This
);
3476 if (!GL_SUPPORT(NV_REGISTER_COMBINERS
) || This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3477 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3478 if (!This
->fixed_function_usage_map
[i
]) continue;
3480 if (This
->texUnitMap
[i
] != i
) {
3481 device_map_stage(This
, i
, i
);
3482 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3483 markTextureStagesDirty(This
, i
);
3489 /* Now work out the mapping */
3491 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3492 if (!This
->fixed_function_usage_map
[i
]) continue;
3494 if (This
->texUnitMap
[i
] != tex
) {
3495 device_map_stage(This
, i
, tex
);
3496 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3497 markTextureStagesDirty(This
, i
);
3504 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3505 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3508 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3509 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3510 device_map_stage(This
, i
, i
);
3511 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3512 if (i
< MAX_TEXTURES
) {
3513 markTextureStagesDirty(This
, i
);
3519 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3520 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3522 if (current_mapping
== -1) {
3523 /* Not currently used */
3527 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3528 /* Used by a fragment sampler */
3530 if (!pshader_sampler_tokens
) {
3531 /* No pixel shader, check fixed function */
3532 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3535 /* Pixel shader, check the shader's sampler map */
3536 return !pshader_sampler_tokens
[current_mapping
];
3539 /* Used by a vertex sampler */
3540 return !vshader_sampler_tokens
[current_mapping
];
3543 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3544 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3545 DWORD
*pshader_sampler_tokens
= NULL
;
3546 int start
= GL_LIMITS(combined_samplers
) - 1;
3550 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3552 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3553 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3554 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3557 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3558 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3559 if (vshader_sampler_tokens
[i
]) {
3560 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3561 /* Already mapped somewhere */
3565 while (start
>= 0) {
3566 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3567 device_map_stage(This
, vsampler_idx
, start
);
3568 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3580 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3581 BOOL vs
= use_vs(This
);
3582 BOOL ps
= use_ps(This
);
3585 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3586 * that would be really messy and require shader recompilation
3587 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3588 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3591 device_map_psamplers(This
);
3593 device_map_fixed_function_samplers(This
);
3597 device_map_vsamplers(This
, ps
);
3601 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3602 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3603 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3604 This
->updateStateBlock
->pixelShader
= pShader
;
3605 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3607 /* Handle recording of state blocks */
3608 if (This
->isRecordingState
) {
3609 TRACE("Recording... not performing anything\n");
3612 if (This
->isRecordingState
) {
3613 TRACE("Recording... not performing anything\n");
3614 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3615 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3619 if(pShader
== oldShader
) {
3620 TRACE("App is setting the old pixel shader over, nothing to do\n");
3624 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3625 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3627 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3628 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3633 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3634 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3636 if (NULL
== ppShader
) {
3637 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3638 return WINED3DERR_INVALIDCALL
;
3641 *ppShader
= This
->stateBlock
->pixelShader
;
3642 if (NULL
!= *ppShader
) {
3643 IWineD3DPixelShader_AddRef(*ppShader
);
3645 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3649 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3650 IWineD3DDevice
*iface
,
3652 CONST BOOL
*srcData
,
3655 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3656 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3658 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3659 iface
, srcData
, start
, count
);
3661 if (srcData
== NULL
|| cnt
< 0)
3662 return WINED3DERR_INVALIDCALL
;
3664 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3665 for (i
= 0; i
< cnt
; i
++)
3666 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3668 for (i
= start
; i
< cnt
+ start
; ++i
) {
3669 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3672 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3677 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3678 IWineD3DDevice
*iface
,
3683 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3684 int cnt
= min(count
, MAX_CONST_B
- start
);
3686 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3687 iface
, dstData
, start
, count
);
3689 if (dstData
== NULL
|| cnt
< 0)
3690 return WINED3DERR_INVALIDCALL
;
3692 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3696 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3697 IWineD3DDevice
*iface
,
3702 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3703 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3705 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3706 iface
, srcData
, start
, count
);
3708 if (srcData
== NULL
|| cnt
< 0)
3709 return WINED3DERR_INVALIDCALL
;
3711 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3712 for (i
= 0; i
< cnt
; i
++)
3713 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3714 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3716 for (i
= start
; i
< cnt
+ start
; ++i
) {
3717 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3720 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3725 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3726 IWineD3DDevice
*iface
,
3731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3732 int cnt
= min(count
, MAX_CONST_I
- start
);
3734 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3735 iface
, dstData
, start
, count
);
3737 if (dstData
== NULL
|| cnt
< 0)
3738 return WINED3DERR_INVALIDCALL
;
3740 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3744 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3745 IWineD3DDevice
*iface
,
3747 CONST
float *srcData
,
3750 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3753 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3754 iface
, srcData
, start
, count
);
3756 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3757 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3758 return WINED3DERR_INVALIDCALL
;
3760 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3762 for (i
= 0; i
< count
; i
++)
3763 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3764 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3767 for (i
= start
; i
< count
+ start
; ++i
) {
3768 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
3769 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
3770 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3771 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3772 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3774 ptr
->idx
[ptr
->count
++] = i
;
3775 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3779 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3784 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3785 IWineD3DDevice
*iface
,
3790 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3791 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3793 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3794 iface
, dstData
, start
, count
);
3796 if (dstData
== NULL
|| cnt
< 0)
3797 return WINED3DERR_INVALIDCALL
;
3799 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3803 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3805 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3806 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3808 DWORD DestFVF
= dest
->fvf
;
3810 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3814 if (lpStrideData
->u
.s
.normal
.lpData
) {
3815 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3818 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
3819 ERR("Source has no position mask\n");
3820 return WINED3DERR_INVALIDCALL
;
3823 /* We might access VBOs from this code, so hold the lock */
3826 if (dest
->resource
.allocatedMemory
== NULL
) {
3827 /* This may happen if we do direct locking into a vbo. Unlikely,
3828 * but theoretically possible(ddraw processvertices test)
3830 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3831 if(!dest
->resource
.allocatedMemory
) {
3833 ERR("Out of memory\n");
3834 return E_OUTOFMEMORY
;
3838 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3839 checkGLcall("glBindBufferARB");
3840 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3842 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3844 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3845 checkGLcall("glUnmapBufferARB");
3849 /* Get a pointer into the destination vbo(create one if none exists) and
3850 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3852 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3857 unsigned char extrabytes
= 0;
3858 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3859 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3860 * this may write 4 extra bytes beyond the area that should be written
3862 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3863 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3864 if(!dest_conv_addr
) {
3865 ERR("Out of memory\n");
3866 /* Continue without storing converted vertices */
3868 dest_conv
= dest_conv_addr
;
3872 * a) WINED3DRS_CLIPPING is enabled
3873 * b) WINED3DVOP_CLIP is passed
3875 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3876 static BOOL warned
= FALSE
;
3878 * The clipping code is not quite correct. Some things need
3879 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3880 * so disable clipping for now.
3881 * (The graphics in Half-Life are broken, and my processvertices
3882 * test crashes with IDirect3DDevice3)
3888 FIXME("Clipping is broken and disabled for now\n");
3890 } else doClip
= FALSE
;
3891 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3893 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3896 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3897 WINED3DTS_PROJECTION
,
3899 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3900 WINED3DTS_WORLDMATRIX(0),
3903 TRACE("View mat:\n");
3904 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
);
3905 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
);
3906 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
);
3907 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
);
3909 TRACE("Proj mat:\n");
3910 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
);
3911 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
);
3912 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
);
3913 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
);
3915 TRACE("World mat:\n");
3916 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
);
3917 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
);
3918 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
);
3919 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
);
3921 /* Get the viewport */
3922 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3923 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3924 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3926 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3927 multiply_matrix(&mat
,&proj_mat
,&mat
);
3929 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3931 for (i
= 0; i
< dwCount
; i
+= 1) {
3932 unsigned int tex_index
;
3934 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3935 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3936 /* The position first */
3938 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
3940 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3942 /* Multiplication with world, view and projection matrix */
3943 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
);
3944 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
);
3945 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
);
3946 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
);
3948 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3950 /* WARNING: The following things are taken from d3d7 and were not yet checked
3951 * against d3d8 or d3d9!
3954 /* Clipping conditions: From
3955 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3957 * A vertex is clipped if it does not match the following requirements
3961 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3963 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3964 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3969 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3970 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3973 /* "Normal" viewport transformation (not clipped)
3974 * 1) The values are divided by rhw
3975 * 2) The y axis is negative, so multiply it with -1
3976 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3977 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3978 * 4) Multiply x with Width/2 and add Width/2
3979 * 5) The same for the height
3980 * 6) Add the viewpoint X and Y to the 2D coordinates and
3981 * The minimum Z value to z
3982 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3984 * Well, basically it's simply a linear transformation into viewport
3996 z
*= vp
.MaxZ
- vp
.MinZ
;
3998 x
+= vp
.Width
/ 2 + vp
.X
;
3999 y
+= vp
.Height
/ 2 + vp
.Y
;
4004 /* That vertex got clipped
4005 * Contrary to OpenGL it is not dropped completely, it just
4006 * undergoes a different calculation.
4008 TRACE("Vertex got clipped\n");
4015 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4016 * outside of the main vertex buffer memory. That needs some more
4021 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4024 ( (float *) dest_ptr
)[0] = x
;
4025 ( (float *) dest_ptr
)[1] = y
;
4026 ( (float *) dest_ptr
)[2] = z
;
4027 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4029 dest_ptr
+= 3 * sizeof(float);
4031 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4032 dest_ptr
+= sizeof(float);
4037 ( (float *) dest_conv
)[0] = x
* w
;
4038 ( (float *) dest_conv
)[1] = y
* w
;
4039 ( (float *) dest_conv
)[2] = z
* w
;
4040 ( (float *) dest_conv
)[3] = w
;
4042 dest_conv
+= 3 * sizeof(float);
4044 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4045 dest_conv
+= sizeof(float);
4049 if (DestFVF
& WINED3DFVF_PSIZE
) {
4050 dest_ptr
+= sizeof(DWORD
);
4051 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4053 if (DestFVF
& WINED3DFVF_NORMAL
) {
4055 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4056 /* AFAIK this should go into the lighting information */
4057 FIXME("Didn't expect the destination to have a normal\n");
4058 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4060 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4064 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4066 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4068 static BOOL warned
= FALSE
;
4071 ERR("No diffuse color in source, but destination has one\n");
4075 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4076 dest_ptr
+= sizeof(DWORD
);
4079 *( (DWORD
*) dest_conv
) = 0xffffffff;
4080 dest_conv
+= sizeof(DWORD
);
4084 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4086 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4087 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4088 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4089 dest_conv
+= sizeof(DWORD
);
4094 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4095 /* What's the color value in the feedback buffer? */
4097 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4099 static BOOL warned
= FALSE
;
4102 ERR("No specular color in source, but destination has one\n");
4106 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4107 dest_ptr
+= sizeof(DWORD
);
4110 *( (DWORD
*) dest_conv
) = 0xFF000000;
4111 dest_conv
+= sizeof(DWORD
);
4115 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4117 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4118 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4119 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4120 dest_conv
+= sizeof(DWORD
);
4125 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4127 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4128 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4130 ERR("No source texture, but destination requests one\n");
4131 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4132 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4135 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4137 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4144 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4145 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4146 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4147 dwCount
* get_flexible_vertex_size(DestFVF
),
4149 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4150 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4157 #undef copy_and_next
4159 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4161 WineDirect3DVertexStridedData strided
;
4162 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4163 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4166 ERR("Output vertex declaration not implemented yet\n");
4169 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4170 * and this call is quite performance critical, so don't call needlessly
4172 if(This
->createParms
.BehaviorFlags
& WINED3DCREATE_MULTITHREADED
) {
4173 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4176 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4177 * control the streamIsUP flag, thus restore it afterwards.
4179 This
->stateBlock
->streamIsUP
= FALSE
;
4180 memset(&strided
, 0, sizeof(strided
));
4181 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4182 This
->stateBlock
->streamIsUP
= streamWasUP
;
4184 if(vbo
|| SrcStartIndex
) {
4186 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4187 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4189 * Also get the start index in, but only loop over all elements if there's something to add at all.
4191 #define FIXSRC(type) \
4192 if(strided.u.s.type.VBO) { \
4193 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4194 strided.u.s.type.VBO = 0; \
4195 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4197 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4201 if(strided.u.s.type.lpData) { \
4202 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4205 FIXSRC(blendWeights
);
4206 FIXSRC(blendMatrixIndices
);
4211 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4212 FIXSRC(texCoords
[i
]);
4225 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4229 * Get / Set Texture Stage States
4230 * TODO: Verify against dx9 definitions
4232 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4233 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4234 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4236 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4238 if (Stage
>= MAX_TEXTURES
) {
4239 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4243 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4244 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4246 if (This
->isRecordingState
) {
4247 TRACE("Recording... not performing anything\n");
4251 /* Checked after the assignments to allow proper stateblock recording */
4252 if(oldValue
== Value
) {
4253 TRACE("App is setting the old value over, nothing to do\n");
4257 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4258 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4259 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4260 * Changes in other states are important on disabled stages too
4265 if(Type
== WINED3DTSS_COLOROP
) {
4268 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4269 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4270 * they have to be disabled
4272 * The current stage is dirtified below.
4274 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4275 TRACE("Additionally dirtifying stage %d\n", i
);
4276 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4278 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4279 TRACE("New lowest disabled: %d\n", Stage
);
4280 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4281 /* Previously disabled stage enabled. Stages above it may need enabling
4282 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4283 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4285 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4288 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4289 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4292 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4293 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4295 This
->stateBlock
->lowest_disabled_stage
= i
;
4296 TRACE("New lowest disabled: %d\n", i
);
4298 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4299 /* TODO: Built a stage -> texture unit mapping for register combiners */
4303 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4308 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4309 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4310 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4311 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4318 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4319 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4320 IWineD3DBaseTexture
*oldTexture
;
4322 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4324 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4325 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4328 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4330 if(pTexture
!= NULL
) {
4331 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4333 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4334 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4335 return WINED3DERR_INVALIDCALL
;
4337 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4340 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4341 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4343 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4344 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4345 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4347 /* Handle recording of state blocks */
4348 if (This
->isRecordingState
) {
4349 TRACE("Recording... not performing anything\n");
4353 if(oldTexture
== pTexture
) {
4354 TRACE("App is setting the same texture again, nothing to do\n");
4358 /** NOTE: MSDN says that setTexture increases the reference count,
4359 * and that the application must set the texture back to null (or have a leaky application),
4360 * This means we should pass the refcount up to the parent
4361 *******************************/
4362 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4363 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4364 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4366 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4367 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4368 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4369 * so the COLOROP and ALPHAOP have to be dirtified.
4371 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4372 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4374 if(bindCount
== 1) {
4375 new->baseTexture
.sampler
= Stage
;
4377 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4381 if (NULL
!= oldTexture
) {
4382 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4383 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4385 IWineD3DBaseTexture_Release(oldTexture
);
4386 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4387 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4388 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4391 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4393 /* Have to do a search for the other sampler(s) where the texture is bound to
4394 * Shouldn't happen as long as apps bind a texture only to one stage
4396 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4397 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4398 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4399 old
->baseTexture
.sampler
= i
;
4406 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4411 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4412 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4414 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4416 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4417 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4420 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4422 IWineD3DBaseTexture_AddRef(*ppTexture
);
4424 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4432 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4433 IWineD3DSurface
**ppBackBuffer
) {
4434 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4435 IWineD3DSwapChain
*swapChain
;
4438 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4440 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4441 if (hr
== WINED3D_OK
) {
4442 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4443 IWineD3DSwapChain_Release(swapChain
);
4445 *ppBackBuffer
= NULL
;
4450 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4451 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4452 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4453 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4456 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4457 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4458 IWineD3DSwapChain
*swapChain
;
4461 if(iSwapChain
> 0) {
4462 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4463 if (hr
== WINED3D_OK
) {
4464 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4465 IWineD3DSwapChain_Release(swapChain
);
4467 FIXME("(%p) Error getting display mode\n", This
);
4470 /* Don't read the real display mode,
4471 but return the stored mode instead. X11 can't change the color
4472 depth, and some apps are pretty angry if they SetDisplayMode from
4473 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4475 Also don't relay to the swapchain because with ddraw it's possible
4476 that there isn't a swapchain at all */
4477 pMode
->Width
= This
->ddraw_width
;
4478 pMode
->Height
= This
->ddraw_height
;
4479 pMode
->Format
= This
->ddraw_format
;
4480 pMode
->RefreshRate
= 0;
4487 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4489 TRACE("(%p)->(%p)\n", This
, hWnd
);
4491 if(This
->ddraw_fullscreen
) {
4492 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4493 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4495 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4496 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4500 This
->ddraw_window
= hWnd
;
4504 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4505 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4506 TRACE("(%p)->(%p)\n", This
, hWnd
);
4508 *hWnd
= This
->ddraw_window
;
4513 * Stateblock related functions
4516 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4517 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4518 IWineD3DStateBlockImpl
*object
;
4519 HRESULT temp_result
;
4522 TRACE("(%p)\n", This
);
4524 if (This
->isRecordingState
) {
4525 return WINED3DERR_INVALIDCALL
;
4528 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4529 if (NULL
== object
) {
4530 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4531 return E_OUTOFMEMORY
;
4533 TRACE("(%p) created object %p\n", This
, object
);
4534 object
->wineD3DDevice
= This
;
4535 /** FIXME: object->parent = parent; **/
4536 object
->parent
= NULL
;
4537 object
->blockType
= WINED3DSBT_RECORDED
;
4539 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4541 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4542 list_init(&object
->lightMap
[i
]);
4545 temp_result
= allocate_shader_constants(object
);
4546 if (WINED3D_OK
!= temp_result
)
4549 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4550 This
->updateStateBlock
= object
;
4551 This
->isRecordingState
= TRUE
;
4553 TRACE("(%p) recording stateblock %p\n",This
, object
);
4557 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4558 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4560 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4562 if (!This
->isRecordingState
) {
4563 FIXME("(%p) not recording! returning error\n", This
);
4564 *ppStateBlock
= NULL
;
4565 return WINED3DERR_INVALIDCALL
;
4568 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4569 if(object
->changed
.renderState
[i
]) {
4570 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4571 object
->num_contained_render_states
++;
4574 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4575 if(object
->changed
.transform
[i
]) {
4576 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4577 object
->num_contained_transform_states
++;
4580 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4581 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4582 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4583 object
->num_contained_vs_consts_f
++;
4586 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4587 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4588 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4589 object
->num_contained_vs_consts_i
++;
4592 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4593 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4594 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4595 object
->num_contained_vs_consts_b
++;
4598 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4599 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4600 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4601 object
->num_contained_ps_consts_i
++;
4604 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4605 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4606 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4607 object
->num_contained_ps_consts_b
++;
4610 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4611 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4612 if(object
->changed
.textureState
[i
][j
]) {
4613 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4614 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4615 object
->num_contained_tss_states
++;
4619 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4620 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4621 if(object
->changed
.samplerState
[i
][j
]) {
4622 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4623 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4624 object
->num_contained_sampler_states
++;
4629 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4630 This
->isRecordingState
= FALSE
;
4631 This
->updateStateBlock
= This
->stateBlock
;
4632 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4633 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4634 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4639 * Scene related functions
4641 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4642 /* At the moment we have no need for any functionality at the beginning
4644 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4645 TRACE("(%p)\n", This
);
4648 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4649 return WINED3DERR_INVALIDCALL
;
4651 This
->inScene
= TRUE
;
4655 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4656 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4657 TRACE("(%p)\n", This
);
4659 if(!This
->inScene
) {
4660 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4661 return WINED3DERR_INVALIDCALL
;
4664 if(This
->createParms
.BehaviorFlags
& WINED3DCREATE_MULTITHREADED
) {
4665 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4667 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4670 checkGLcall("glFlush");
4673 This
->inScene
= FALSE
;
4677 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4678 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4679 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4680 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4681 IWineD3DSwapChain
*swapChain
= NULL
;
4683 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4685 TRACE("(%p) Presenting the frame\n", This
);
4687 for(i
= 0 ; i
< swapchains
; i
++) {
4689 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4690 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4691 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4692 IWineD3DSwapChain_Release(swapChain
);
4698 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4699 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4700 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4701 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4703 GLbitfield glMask
= 0;
4705 CONST WINED3DRECT
* curRect
;
4707 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4708 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4710 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4711 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4712 /* TODO: What about depth stencil buffers without stencil bits? */
4713 return WINED3DERR_INVALIDCALL
;
4716 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4717 * and not the last active one.
4719 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_CLEAR
);
4722 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4723 apply_fbo_state(iface
);
4726 if (Count
> 0 && pRects
) {
4732 /* Only set the values up once, as they are not changing */
4733 if (Flags
& WINED3DCLEAR_STENCIL
) {
4734 glClearStencil(Stencil
);
4735 checkGLcall("glClearStencil");
4736 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4737 glStencilMask(0xFFFFFFFF);
4740 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4741 glDepthMask(GL_TRUE
);
4743 checkGLcall("glClearDepth");
4744 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4745 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4748 if (Flags
& WINED3DCLEAR_TARGET
) {
4749 TRACE("Clearing screen with glClear to color %x\n", Color
);
4750 glClearColor(D3DCOLOR_R(Color
),
4754 checkGLcall("glClearColor");
4756 /* Clear ALL colors! */
4757 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4758 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4762 /* In drawable flag is set below */
4764 if (This
->render_offscreen
) {
4765 glScissor(This
->stateBlock
->viewport
.X
,
4766 This
->stateBlock
->viewport
.Y
,
4767 This
->stateBlock
->viewport
.Width
,
4768 This
->stateBlock
->viewport
.Height
);
4770 glScissor(This
->stateBlock
->viewport
.X
,
4771 (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
-
4772 (This
->stateBlock
->viewport
.Y
+ This
->stateBlock
->viewport
.Height
)),
4773 This
->stateBlock
->viewport
.Width
,
4774 This
->stateBlock
->viewport
.Height
);
4776 checkGLcall("glScissor");
4778 checkGLcall("glClear");
4780 if(!(target
->Flags
& SFLAG_INDRAWABLE
) &&
4781 !(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& This
->render_offscreen
&& target
->Flags
& SFLAG_INTEXTURE
)) {
4783 if(curRect
[0].x1
> 0 || curRect
[0].y1
> 0 ||
4784 curRect
[0].x2
< target
->currentDesc
.Width
||
4785 curRect
[0].y2
< target
->currentDesc
.Height
) {
4786 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4787 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4791 /* Now process each rect in turn */
4792 for (i
= 0; i
< Count
; i
++) {
4793 /* Note gl uses lower left, width/height */
4794 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
, curRect
,
4795 curRect
[i
].x1
, curRect
[i
].y1
, curRect
[i
].x2
, curRect
[i
].y2
,
4796 curRect
[i
].x1
, (target
->currentDesc
.Height
- curRect
[i
].y2
),
4797 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4799 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4800 * The rectangle is not cleared, no error is returned, but further rectanlges are
4801 * still cleared if they are valid
4803 if(curRect
[i
].x1
> curRect
[i
].x2
|| curRect
[i
].y1
> curRect
[i
].y2
) {
4804 TRACE("Rectangle with negative dimensions, ignoring\n");
4808 if(This
->render_offscreen
) {
4809 glScissor(curRect
[i
].x1
, curRect
[i
].y1
,
4810 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4812 glScissor(curRect
[i
].x1
, target
->currentDesc
.Height
- curRect
[i
].y2
,
4813 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4815 checkGLcall("glScissor");
4818 checkGLcall("glClear");
4822 /* Restore the old values (why..?) */
4823 if (Flags
& WINED3DCLEAR_STENCIL
) {
4824 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4826 if (Flags
& WINED3DCLEAR_TARGET
) {
4827 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4828 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4829 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4830 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4831 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4836 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4837 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4839 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
4840 /* TODO: Move the fbo logic into ModifyLocation() */
4841 if(This
->render_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4842 target
->Flags
|= SFLAG_INTEXTURE
;
4850 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4851 UINT PrimitiveCount
) {
4853 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4855 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4856 debug_d3dprimitivetype(PrimitiveType
),
4857 StartVertex
, PrimitiveCount
);
4859 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4860 if(This
->stateBlock
->streamIsUP
) {
4861 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4862 This
->stateBlock
->streamIsUP
= FALSE
;
4865 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4866 This
->stateBlock
->loadBaseVertexIndex
= 0;
4867 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4869 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4870 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4871 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4875 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4876 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4877 WINED3DPRIMITIVETYPE PrimitiveType
,
4878 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4880 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4882 IWineD3DIndexBuffer
*pIB
;
4883 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4886 pIB
= This
->stateBlock
->pIndexData
;
4888 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4889 * without an index buffer set. (The first time at least...)
4890 * D3D8 simply dies, but I doubt it can do much harm to return
4891 * D3DERR_INVALIDCALL there as well. */
4892 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4893 return WINED3DERR_INVALIDCALL
;
4896 if(This
->stateBlock
->streamIsUP
) {
4897 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4898 This
->stateBlock
->streamIsUP
= FALSE
;
4900 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
4902 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
4903 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4904 minIndex
, NumVertices
, startIndex
, primCount
);
4906 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
4907 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
4913 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4914 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4915 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4918 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
4919 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
4924 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4925 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
4926 UINT VertexStreamZeroStride
) {
4927 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4928 IWineD3DVertexBuffer
*vb
;
4930 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
4931 debug_d3dprimitivetype(PrimitiveType
),
4932 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4934 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4935 vb
= This
->stateBlock
->streamSource
[0];
4936 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4937 if(vb
) IWineD3DVertexBuffer_Release(vb
);
4938 This
->stateBlock
->streamOffset
[0] = 0;
4939 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4940 This
->stateBlock
->streamIsUP
= TRUE
;
4941 This
->stateBlock
->loadBaseVertexIndex
= 0;
4943 /* TODO: Only mark dirty if drawing from a different UP address */
4944 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4946 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
4947 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
4949 /* MSDN specifies stream zero settings must be set to NULL */
4950 This
->stateBlock
->streamStride
[0] = 0;
4951 This
->stateBlock
->streamSource
[0] = NULL
;
4953 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4954 * the new stream sources or use UP drawing again
4959 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4960 UINT MinVertexIndex
, UINT NumVertices
,
4961 UINT PrimitiveCount
, CONST
void* pIndexData
,
4962 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
4963 UINT VertexStreamZeroStride
) {
4965 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4966 IWineD3DVertexBuffer
*vb
;
4967 IWineD3DIndexBuffer
*ib
;
4969 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4970 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4971 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
4972 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4974 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
4980 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4981 vb
= This
->stateBlock
->streamSource
[0];
4982 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4983 if(vb
) IWineD3DVertexBuffer_Release(vb
);
4984 This
->stateBlock
->streamIsUP
= TRUE
;
4985 This
->stateBlock
->streamOffset
[0] = 0;
4986 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4988 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4989 This
->stateBlock
->baseVertexIndex
= 0;
4990 This
->stateBlock
->loadBaseVertexIndex
= 0;
4991 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4992 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4993 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4995 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
4997 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4998 This
->stateBlock
->streamSource
[0] = NULL
;
4999 This
->stateBlock
->streamStride
[0] = 0;
5000 ib
= This
->stateBlock
->pIndexData
;
5002 IWineD3DIndexBuffer_Release(ib
);
5003 This
->stateBlock
->pIndexData
= NULL
;
5005 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5006 * SetStreamSource to specify a vertex buffer
5012 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5013 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5015 /* Mark the state dirty until we have nicer tracking
5016 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5019 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5020 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5021 This
->stateBlock
->baseVertexIndex
= 0;
5022 This
->up_strided
= DrawPrimStrideData
;
5023 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5024 This
->up_strided
= NULL
;
5028 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5029 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5030 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5032 /* Mark the state dirty until we have nicer tracking
5033 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5036 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5037 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5038 This
->stateBlock
->streamIsUP
= TRUE
;
5039 This
->stateBlock
->baseVertexIndex
= 0;
5040 This
->up_strided
= DrawPrimStrideData
;
5041 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5042 This
->up_strided
= NULL
;
5046 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5047 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5048 * not callable by the app directly no parameter validation checks are needed here.
5050 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5051 WINED3DLOCKED_BOX src
;
5052 WINED3DLOCKED_BOX dst
;
5054 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5056 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5057 * dirtification to improve loading performance.
5059 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5060 if(FAILED(hr
)) return hr
;
5061 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5063 IWineD3DVolume_UnlockBox(pSourceVolume
);
5067 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5069 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5071 IWineD3DVolume_UnlockBox(pSourceVolume
);
5073 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5078 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5079 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5080 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5081 HRESULT hr
= WINED3D_OK
;
5082 WINED3DRESOURCETYPE sourceType
;
5083 WINED3DRESOURCETYPE destinationType
;
5086 /* TODO: think about moving the code into IWineD3DBaseTexture */
5088 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5090 /* verify that the source and destination textures aren't NULL */
5091 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5092 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5093 This
, pSourceTexture
, pDestinationTexture
);
5094 hr
= WINED3DERR_INVALIDCALL
;
5097 if (pSourceTexture
== pDestinationTexture
) {
5098 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5099 This
, pSourceTexture
, pDestinationTexture
);
5100 hr
= WINED3DERR_INVALIDCALL
;
5102 /* Verify that the source and destination textures are the same type */
5103 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5104 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5106 if (sourceType
!= destinationType
) {
5107 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5109 hr
= WINED3DERR_INVALIDCALL
;
5112 /* check that both textures have the identical numbers of levels */
5113 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5114 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5115 hr
= WINED3DERR_INVALIDCALL
;
5118 if (WINED3D_OK
== hr
) {
5120 /* Make sure that the destination texture is loaded */
5121 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5123 /* Update every surface level of the texture */
5124 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5126 switch (sourceType
) {
5127 case WINED3DRTYPE_TEXTURE
:
5129 IWineD3DSurface
*srcSurface
;
5130 IWineD3DSurface
*destSurface
;
5132 for (i
= 0 ; i
< levels
; ++i
) {
5133 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5134 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5135 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5136 IWineD3DSurface_Release(srcSurface
);
5137 IWineD3DSurface_Release(destSurface
);
5138 if (WINED3D_OK
!= hr
) {
5139 WARN("(%p) : Call to update surface failed\n", This
);
5145 case WINED3DRTYPE_CUBETEXTURE
:
5147 IWineD3DSurface
*srcSurface
;
5148 IWineD3DSurface
*destSurface
;
5149 WINED3DCUBEMAP_FACES faceType
;
5151 for (i
= 0 ; i
< levels
; ++i
) {
5152 /* Update each cube face */
5153 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5154 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5155 if (WINED3D_OK
!= hr
) {
5156 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5158 TRACE("Got srcSurface %p\n", srcSurface
);
5160 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5161 if (WINED3D_OK
!= hr
) {
5162 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5164 TRACE("Got desrSurface %p\n", destSurface
);
5166 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5167 IWineD3DSurface_Release(srcSurface
);
5168 IWineD3DSurface_Release(destSurface
);
5169 if (WINED3D_OK
!= hr
) {
5170 WARN("(%p) : Call to update surface failed\n", This
);
5178 case WINED3DRTYPE_VOLUMETEXTURE
:
5180 IWineD3DVolume
*srcVolume
= NULL
;
5181 IWineD3DVolume
*destVolume
= NULL
;
5183 for (i
= 0 ; i
< levels
; ++i
) {
5184 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5185 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5186 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5187 IWineD3DVolume_Release(srcVolume
);
5188 IWineD3DVolume_Release(destVolume
);
5189 if (WINED3D_OK
!= hr
) {
5190 WARN("(%p) : Call to update volume failed\n", This
);
5198 FIXME("(%p) : Unsupported source and destination type\n", This
);
5199 hr
= WINED3DERR_INVALIDCALL
;
5206 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5207 IWineD3DSwapChain
*swapChain
;
5209 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5210 if(hr
== WINED3D_OK
) {
5211 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5212 IWineD3DSwapChain_Release(swapChain
);
5217 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5218 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5219 /* return a sensible default */
5221 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5222 FIXME("(%p) : stub\n", This
);
5226 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5227 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5229 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5230 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5231 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5232 return WINED3DERR_INVALIDCALL
;
5234 for (j
= 0; j
< 256; ++j
) {
5235 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5236 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5237 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5238 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5240 TRACE("(%p) : returning\n", This
);
5244 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5245 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5247 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5248 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5249 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5250 return WINED3DERR_INVALIDCALL
;
5252 for (j
= 0; j
< 256; ++j
) {
5253 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5254 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5255 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5256 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5258 TRACE("(%p) : returning\n", This
);
5262 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5263 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5264 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5265 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5266 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5267 return WINED3DERR_INVALIDCALL
;
5269 /*TODO: stateblocks */
5270 This
->currentPalette
= PaletteNumber
;
5271 TRACE("(%p) : returning\n", This
);
5275 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5277 if (PaletteNumber
== NULL
) {
5278 WARN("(%p) : returning Invalid Call\n", This
);
5279 return WINED3DERR_INVALIDCALL
;
5281 /*TODO: stateblocks */
5282 *PaletteNumber
= This
->currentPalette
;
5283 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5287 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5288 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5289 static BOOL showFixmes
= TRUE
;
5291 FIXME("(%p) : stub\n", This
);
5295 This
->softwareVertexProcessing
= bSoftware
;
5300 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5301 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5302 static BOOL showFixmes
= TRUE
;
5304 FIXME("(%p) : stub\n", This
);
5307 return This
->softwareVertexProcessing
;
5311 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5312 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5313 IWineD3DSwapChain
*swapChain
;
5316 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5318 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5319 if(hr
== WINED3D_OK
){
5320 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5321 IWineD3DSwapChain_Release(swapChain
);
5323 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5329 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5330 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5331 static BOOL showfixmes
= TRUE
;
5332 if(nSegments
!= 0.0f
) {
5334 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5341 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5342 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5343 static BOOL showfixmes
= TRUE
;
5345 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5351 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5352 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5353 /** TODO: remove casts to IWineD3DSurfaceImpl
5354 * NOTE: move code to surface to accomplish this
5355 ****************************************/
5356 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5357 int srcWidth
, srcHeight
;
5358 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5359 WINED3DFORMAT destFormat
, srcFormat
;
5361 int srcLeft
, destLeft
, destTop
;
5362 WINED3DPOOL srcPool
, destPool
;
5364 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5365 glDescriptor
*glDescription
= NULL
;
5368 CONVERT_TYPES convert
= NO_CONVERSION
;
5370 WINED3DSURFACE_DESC winedesc
;
5372 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5373 memset(&winedesc
, 0, sizeof(winedesc
));
5374 winedesc
.Width
= &srcSurfaceWidth
;
5375 winedesc
.Height
= &srcSurfaceHeight
;
5376 winedesc
.Pool
= &srcPool
;
5377 winedesc
.Format
= &srcFormat
;
5379 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5381 winedesc
.Width
= &destSurfaceWidth
;
5382 winedesc
.Height
= &destSurfaceHeight
;
5383 winedesc
.Pool
= &destPool
;
5384 winedesc
.Format
= &destFormat
;
5385 winedesc
.Size
= &destSize
;
5387 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5389 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5390 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5391 return WINED3DERR_INVALIDCALL
;
5394 /* This call loads the opengl surface directly, instead of copying the surface to the
5395 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5396 * copy in sysmem and use regular surface loading.
5398 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5399 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5400 if(convert
!= NO_CONVERSION
) {
5401 return IWineD3DSurface_BltFast(pDestinationSurface
,
5402 pDestPoint
? pDestPoint
->x
: 0,
5403 pDestPoint
? pDestPoint
->y
: 0,
5404 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5407 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5408 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5409 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5411 /* Get the update surface description */
5412 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5415 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5419 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5420 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5421 checkGLcall("glActiveTextureARB");
5424 /* Make sure the surface is loaded and up to date */
5425 IWineD3DSurface_PreLoad(pDestinationSurface
);
5427 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5429 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5430 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5431 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5432 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5433 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5434 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5437 /* This function doesn't support compressed textures
5438 the pitch is just bytesPerPixel * width */
5439 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5440 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5441 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5442 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5444 /* TODO DXT formats */
5446 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5447 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5449 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5451 ,glDescription
->level
5456 ,glDescription
->glFormat
5457 ,glDescription
->glType
5458 ,IWineD3DSurface_GetData(pSourceSurface
)
5462 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5464 /* need to lock the surface to get the data */
5465 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5468 /* TODO: Cube and volume support */
5470 /* not a whole row so we have to do it a line at a time */
5473 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5474 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5476 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5478 glTexSubImage2D(glDescription
->target
5479 ,glDescription
->level
5484 ,glDescription
->glFormat
5485 ,glDescription
->glType
5486 ,data
/* could be quicker using */
5491 } else { /* Full width, so just write out the whole texture */
5493 if (WINED3DFMT_DXT1
== destFormat
||
5494 WINED3DFMT_DXT2
== destFormat
||
5495 WINED3DFMT_DXT3
== destFormat
||
5496 WINED3DFMT_DXT4
== destFormat
||
5497 WINED3DFMT_DXT5
== destFormat
) {
5498 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5499 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5500 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5501 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5502 } if (destFormat
!= srcFormat
) {
5503 FIXME("Updating mixed format compressed texture is not curretly support\n");
5505 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5506 glDescription
->level
,
5507 glDescription
->glFormatInternal
,
5512 IWineD3DSurface_GetData(pSourceSurface
));
5515 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5520 glTexSubImage2D(glDescription
->target
5521 ,glDescription
->level
5526 ,glDescription
->glFormat
5527 ,glDescription
->glType
5528 ,IWineD3DSurface_GetData(pSourceSurface
)
5532 checkGLcall("glTexSubImage2D");
5536 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5537 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
5542 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5543 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5544 struct WineD3DRectPatch
*patch
;
5548 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5550 if(!(Handle
|| pRectPatchInfo
)) {
5551 /* TODO: Write a test for the return value, thus the FIXME */
5552 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5553 return WINED3DERR_INVALIDCALL
;
5557 i
= PATCHMAP_HASHFUNC(Handle
);
5559 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5560 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5561 if(patch
->Handle
== Handle
) {
5568 TRACE("Patch does not exist. Creating a new one\n");
5569 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5570 patch
->Handle
= Handle
;
5571 list_add_head(&This
->patches
[i
], &patch
->entry
);
5573 TRACE("Found existing patch %p\n", patch
);
5576 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5577 * attributes we have to tesselate, read back, and draw. This needs a patch
5578 * management structure instance. Create one.
5580 * A possible improvement is to check if a vertex shader is used, and if not directly
5583 FIXME("Drawing an uncached patch. This is slow\n");
5584 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5587 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5588 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5589 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5591 TRACE("Tesselation density or patch info changed, retesselating\n");
5593 if(pRectPatchInfo
) {
5594 memcpy(&patch
->RectPatchInfo
, pRectPatchInfo
, sizeof(*pRectPatchInfo
));
5596 patch
->numSegs
[0] = pNumSegs
[0];
5597 patch
->numSegs
[1] = pNumSegs
[1];
5598 patch
->numSegs
[2] = pNumSegs
[2];
5599 patch
->numSegs
[3] = pNumSegs
[3];
5601 hr
= tesselate_rectpatch(This
, patch
);
5603 WARN("Patch tesselation failed\n");
5605 /* Do not release the handle to store the params of the patch */
5607 HeapFree(GetProcessHeap(), 0, patch
);
5613 This
->currentPatch
= patch
;
5614 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
5615 This
->currentPatch
= NULL
;
5617 /* Destroy uncached patches */
5619 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5620 HeapFree(GetProcessHeap(), 0, patch
);
5625 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5626 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5627 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5628 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5629 FIXME("(%p) : Stub\n", This
);
5633 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5634 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5636 struct WineD3DRectPatch
*patch
;
5638 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5640 i
= PATCHMAP_HASHFUNC(Handle
);
5641 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5642 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5643 if(patch
->Handle
== Handle
) {
5644 TRACE("Deleting patch %p\n", patch
);
5645 list_remove(&patch
->entry
);
5646 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5647 HeapFree(GetProcessHeap(), 0, patch
);
5652 /* TODO: Write a test for the return value */
5653 FIXME("Attempt to destroy nonexistant patch\n");
5654 return WINED3DERR_INVALIDCALL
;
5657 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5659 IWineD3DSwapChain
*swapchain
;
5661 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5662 if (SUCCEEDED(hr
)) {
5663 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5670 static void bind_fbo(IWineD3DDevice
*iface
, GLenum target
, GLuint
*fbo
) {
5671 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5674 GL_EXTCALL(glGenFramebuffersEXT(1, fbo
));
5675 checkGLcall("glGenFramebuffersEXT()");
5677 GL_EXTCALL(glBindFramebufferEXT(target
, *fbo
));
5678 checkGLcall("glBindFramebuffer()");
5681 static void attach_surface_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, DWORD idx
, IWineD3DSurface
*surface
) {
5682 const IWineD3DSurfaceImpl
*surface_impl
= (IWineD3DSurfaceImpl
*)surface
;
5683 IWineD3DBaseTextureImpl
*texture_impl
;
5684 GLenum texttarget
, target
;
5687 texttarget
= surface_impl
->glDescription
.target
;
5688 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5689 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5691 IWineD3DSurface_PreLoad(surface
);
5693 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5694 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5695 glBindTexture(target
, old_binding
);
5697 /* Update base texture states array */
5698 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
5699 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
5700 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
5701 if (texture_impl
->baseTexture
.bindCount
) {
5702 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
5705 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
5708 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
,
5709 surface_impl
->glDescription
.textureName
, surface_impl
->glDescription
.level
));
5711 checkGLcall("attach_surface_fbo");
5714 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
5715 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5716 IWineD3DSwapChain
*swapchain
;
5718 swapchain
= get_swapchain(surface
);
5722 TRACE("Surface %p is onscreen\n", surface
);
5724 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5725 buffer
= surface_get_gl_buffer(surface
, swapchain
);
5726 glDrawBuffer(buffer
);
5727 checkGLcall("glDrawBuffer()");
5729 TRACE("Surface %p is offscreen\n", surface
);
5730 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
5731 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
5735 glEnable(GL_SCISSOR_TEST
);
5737 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5739 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5740 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5742 checkGLcall("glScissor");
5744 glDisable(GL_SCISSOR_TEST
);
5746 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5748 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5749 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5751 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
5752 glClear(GL_COLOR_BUFFER_BIT
);
5753 checkGLcall("glClear");
5755 if (This
->render_offscreen
) {
5756 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
5758 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5759 checkGLcall("glBindFramebuffer()");
5762 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
5763 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
5764 glDrawBuffer(GL_BACK
);
5765 checkGLcall("glDrawBuffer()");
5769 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5770 unsigned int r
, g
, b
, a
;
5773 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
5774 destfmt
== WINED3DFMT_R8G8B8
)
5777 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5779 a
= (color
& 0xff000000) >> 24;
5780 r
= (color
& 0x00ff0000) >> 16;
5781 g
= (color
& 0x0000ff00) >> 8;
5782 b
= (color
& 0x000000ff) >> 0;
5786 case WINED3DFMT_R5G6B5
:
5787 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5794 TRACE("Returning %08x\n", ret
);
5797 case WINED3DFMT_X1R5G5B5
:
5798 case WINED3DFMT_A1R5G5B5
:
5807 TRACE("Returning %08x\n", ret
);
5811 TRACE("Returning %08x\n", a
);
5814 case WINED3DFMT_X4R4G4B4
:
5815 case WINED3DFMT_A4R4G4B4
:
5824 TRACE("Returning %08x\n", ret
);
5827 case WINED3DFMT_R3G3B2
:
5834 TRACE("Returning %08x\n", ret
);
5837 case WINED3DFMT_X8B8G8R8
:
5838 case WINED3DFMT_A8B8G8R8
:
5843 TRACE("Returning %08x\n", ret
);
5846 case WINED3DFMT_A2R10G10B10
:
5848 r
= (r
* 1024) / 256;
5849 g
= (g
* 1024) / 256;
5850 b
= (b
* 1024) / 256;
5855 TRACE("Returning %08x\n", ret
);
5858 case WINED3DFMT_A2B10G10R10
:
5860 r
= (r
* 1024) / 256;
5861 g
= (g
* 1024) / 256;
5862 b
= (b
* 1024) / 256;
5867 TRACE("Returning %08x\n", ret
);
5871 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5876 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5877 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5878 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5880 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
5882 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5883 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5884 return WINED3DERR_INVALIDCALL
;
5887 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5888 color_fill_fbo(iface
, pSurface
, pRect
, color
);
5891 /* Just forward this to the DirectDraw blitting engine */
5892 memset(&BltFx
, 0, sizeof(BltFx
));
5893 BltFx
.dwSize
= sizeof(BltFx
);
5894 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
5895 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
5899 /* rendertarget and deptth stencil functions */
5900 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5901 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5903 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5904 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5905 return WINED3DERR_INVALIDCALL
;
5908 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5909 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5910 /* Note inc ref on returned surface */
5911 if(*ppRenderTarget
!= NULL
)
5912 IWineD3DSurface_AddRef(*ppRenderTarget
);
5916 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
5917 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5918 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5919 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5920 IWineD3DSwapChainImpl
*Swapchain
;
5923 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
5925 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5926 if(hr
!= WINED3D_OK
) {
5927 ERR("Can't get the swapchain\n");
5931 /* Make sure to release the swapchain */
5932 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5934 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5935 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5936 return WINED3DERR_INVALIDCALL
;
5938 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5939 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5940 return WINED3DERR_INVALIDCALL
;
5943 if(Swapchain
->frontBuffer
!= Front
) {
5944 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5946 if(Swapchain
->frontBuffer
)
5947 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5948 Swapchain
->frontBuffer
= Front
;
5950 if(Swapchain
->frontBuffer
) {
5951 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5955 if(Back
&& !Swapchain
->backBuffer
) {
5956 /* We need memory for the back buffer array - only one back buffer this way */
5957 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
5958 if(!Swapchain
->backBuffer
) {
5959 ERR("Out of memory\n");
5960 return E_OUTOFMEMORY
;
5964 if(Swapchain
->backBuffer
[0] != Back
) {
5965 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
5967 /* What to do about the context here in the case of multithreading? Not sure.
5968 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5971 if(!Swapchain
->backBuffer
[0]) {
5972 /* GL was told to draw to the front buffer at creation,
5975 glDrawBuffer(GL_BACK
);
5976 checkGLcall("glDrawBuffer(GL_BACK)");
5977 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5978 Swapchain
->presentParms
.BackBufferCount
= 1;
5980 /* That makes problems - disable for now */
5981 /* glDrawBuffer(GL_FRONT); */
5982 checkGLcall("glDrawBuffer(GL_FRONT)");
5983 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5984 Swapchain
->presentParms
.BackBufferCount
= 0;
5988 if(Swapchain
->backBuffer
[0])
5989 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5990 Swapchain
->backBuffer
[0] = Back
;
5992 if(Swapchain
->backBuffer
[0]) {
5993 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
5995 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6003 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6004 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6005 *ppZStencilSurface
= This
->depthStencilBuffer
;
6006 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6008 if(*ppZStencilSurface
!= NULL
) {
6009 /* Note inc ref on returned surface */
6010 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6013 return WINED3DERR_NOTFOUND
;
6017 /* TODO: Handle stencil attachments */
6018 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
6019 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6020 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
6022 TRACE("Set depth stencil to %p\n", depth_stencil
);
6024 if (depth_stencil_impl
) {
6025 if (depth_stencil_impl
->current_renderbuffer
) {
6026 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, depth_stencil_impl
->current_renderbuffer
->id
));
6027 checkGLcall("glFramebufferRenderbufferEXT()");
6029 IWineD3DBaseTextureImpl
*texture_impl
;
6030 GLenum texttarget
, target
;
6031 GLint old_binding
= 0;
6033 texttarget
= depth_stencil_impl
->glDescription
.target
;
6034 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
6035 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6037 IWineD3DSurface_PreLoad(depth_stencil
);
6039 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6040 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6041 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
6042 glBindTexture(target
, old_binding
);
6044 /* Update base texture states array */
6045 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6046 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6047 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6048 if (texture_impl
->baseTexture
.bindCount
) {
6049 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6052 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6055 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
,
6056 depth_stencil_impl
->glDescription
.textureName
, depth_stencil_impl
->glDescription
.level
));
6057 checkGLcall("glFramebufferTexture2DEXT()");
6060 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
6061 checkGLcall("glFramebufferTexture2DEXT()");
6065 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
6066 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6067 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
6069 TRACE("Set render target %u to %p\n", idx
, render_target
);
6072 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, idx
, render_target
);
6073 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
6075 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
6076 checkGLcall("glFramebufferTexture2DEXT()");
6078 This
->draw_buffers
[idx
] = GL_NONE
;
6082 static void check_fbo_status(IWineD3DDevice
*iface
) {
6083 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6086 status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
6087 if (status
== GL_FRAMEBUFFER_COMPLETE_EXT
) {
6088 TRACE("FBO complete\n");
6090 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status
), status
);
6092 /* Dump the FBO attachments */
6093 if (status
== GL_FRAMEBUFFER_UNSUPPORTED_EXT
) {
6094 IWineD3DSurfaceImpl
*attachment
;
6097 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6098 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_color_attachments
[i
];
6100 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i
, attachment
, debug_d3dformat(attachment
->resource
.format
),
6101 attachment
->pow2Width
, attachment
->pow2Height
);
6104 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_depth_attachment
;
6106 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment
, debug_d3dformat(attachment
->resource
.format
),
6107 attachment
->pow2Width
, attachment
->pow2Height
);
6113 static BOOL
depth_mismatch_fbo(IWineD3DDevice
*iface
) {
6114 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6115 IWineD3DSurfaceImpl
*rt_impl
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
6116 IWineD3DSurfaceImpl
*ds_impl
= (IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
;
6118 if (!ds_impl
) return FALSE
;
6120 if (ds_impl
->current_renderbuffer
) {
6121 return (rt_impl
->pow2Width
!= ds_impl
->current_renderbuffer
->width
||
6122 rt_impl
->pow2Height
!= ds_impl
->current_renderbuffer
->height
);
6125 return (rt_impl
->pow2Width
!= ds_impl
->pow2Width
||
6126 rt_impl
->pow2Height
!= ds_impl
->pow2Height
);
6129 void apply_fbo_state(IWineD3DDevice
*iface
) {
6130 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6133 if (This
->render_offscreen
) {
6134 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6136 /* Apply render targets */
6137 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6138 IWineD3DSurface
*render_target
= This
->render_targets
[i
];
6139 if (This
->fbo_color_attachments
[i
] != render_target
) {
6140 set_render_target_fbo(iface
, i
, render_target
);
6141 This
->fbo_color_attachments
[i
] = render_target
;
6145 /* Apply depth targets */
6146 if (This
->fbo_depth_attachment
!= This
->stencilBufferTarget
|| depth_mismatch_fbo(iface
)) {
6147 unsigned int w
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Width
;
6148 unsigned int h
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Height
;
6150 if (This
->stencilBufferTarget
) {
6151 surface_set_compatible_renderbuffer(This
->stencilBufferTarget
, w
, h
);
6153 set_depth_stencil_fbo(iface
, This
->stencilBufferTarget
);
6154 This
->fbo_depth_attachment
= This
->stencilBufferTarget
;
6157 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
6158 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
6159 checkGLcall("glDrawBuffers()");
6161 glDrawBuffer(This
->draw_buffers
[0]);
6162 checkGLcall("glDrawBuffer()");
6165 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6168 check_fbo_status(iface
);
6171 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6172 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6173 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6174 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6175 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6178 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6179 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6180 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6181 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6184 case WINED3DTEXF_LINEAR
:
6185 gl_filter
= GL_LINEAR
;
6189 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6190 case WINED3DTEXF_NONE
:
6191 case WINED3DTEXF_POINT
:
6192 gl_filter
= GL_NEAREST
;
6196 /* Attach src surface to src fbo */
6197 src_swapchain
= get_swapchain(src_surface
);
6198 if (src_swapchain
) {
6201 TRACE("Source surface %p is onscreen\n", src_surface
);
6202 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6205 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6206 buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6207 glReadBuffer(buffer
);
6208 checkGLcall("glReadBuffer()");
6210 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6211 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6213 TRACE("Source surface %p is offscreen\n", src_surface
);
6215 bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->src_fbo
);
6216 attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6217 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6218 checkGLcall("glReadBuffer()");
6222 /* Attach dst surface to dst fbo */
6223 dst_swapchain
= get_swapchain(dst_surface
);
6224 if (dst_swapchain
) {
6227 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6228 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6231 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6232 buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6233 glDrawBuffer(buffer
);
6234 checkGLcall("glDrawBuffer()");
6236 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6237 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6239 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6241 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6242 if(!src_swapchain
) {
6243 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6247 bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6248 attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6249 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6250 checkGLcall("glDrawBuffer()");
6252 glDisable(GL_SCISSOR_TEST
);
6253 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6256 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6257 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6258 checkGLcall("glBlitFramebuffer()");
6260 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6261 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6262 checkGLcall("glBlitFramebuffer()");
6265 if (This
->render_offscreen
) {
6266 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6268 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6269 checkGLcall("glBindFramebuffer()");
6272 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6273 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6274 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6275 glDrawBuffer(GL_BACK
);
6276 checkGLcall("glDrawBuffer()");
6281 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6282 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6283 WINED3DVIEWPORT viewport
;
6285 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6287 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6288 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6289 return WINED3DERR_INVALIDCALL
;
6292 /* MSDN says that null disables the render target
6293 but a device must always be associated with a render target
6294 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6296 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6299 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6300 FIXME("Trying to set render target 0 to NULL\n");
6301 return WINED3DERR_INVALIDCALL
;
6303 if (pRenderTarget
&& !((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
6304 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
);
6305 return WINED3DERR_INVALIDCALL
;
6308 /* If we are trying to set what we already have, don't bother */
6309 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6310 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6313 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6314 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6315 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6317 /* Render target 0 is special */
6318 if(RenderTargetIndex
== 0) {
6319 /* Finally, reset the viewport as the MSDN states. */
6320 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6321 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6324 viewport
.MaxZ
= 1.0f
;
6325 viewport
.MinZ
= 0.0f
;
6326 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6327 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6328 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6330 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6332 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6334 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6335 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6337 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6342 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6343 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6344 HRESULT hr
= WINED3D_OK
;
6345 IWineD3DSurface
*tmp
;
6347 TRACE("(%p) Swapping z-buffer\n",This
);
6349 if (pNewZStencil
== This
->stencilBufferTarget
) {
6350 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6352 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6353 * depending on the renter target implementation being used.
6354 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6355 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6356 * stencil buffer and incure an extra memory overhead
6357 ******************************************************/
6359 tmp
= This
->stencilBufferTarget
;
6360 This
->stencilBufferTarget
= pNewZStencil
;
6361 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
6362 /* should we be calling the parent or the wined3d surface? */
6363 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6364 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6367 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6368 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6369 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6370 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6371 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6378 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6379 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6380 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6381 /* TODO: the use of Impl is deprecated. */
6382 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6383 WINED3DLOCKED_RECT lockedRect
;
6385 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6387 /* some basic validation checks */
6388 if(This
->cursorTexture
) {
6389 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6391 glDeleteTextures(1, &This
->cursorTexture
);
6393 This
->cursorTexture
= 0;
6396 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6397 This
->haveHardwareCursor
= TRUE
;
6399 This
->haveHardwareCursor
= FALSE
;
6402 WINED3DLOCKED_RECT rect
;
6404 /* MSDN: Cursor must be A8R8G8B8 */
6405 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6406 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6407 return WINED3DERR_INVALIDCALL
;
6410 /* MSDN: Cursor must be smaller than the display mode */
6411 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6412 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6413 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
);
6414 return WINED3DERR_INVALIDCALL
;
6417 if (!This
->haveHardwareCursor
) {
6418 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6420 /* Do not store the surface's pointer because the application may
6421 * release it after setting the cursor image. Windows doesn't
6422 * addref the set surface, so we can't do this either without
6423 * creating circular refcount dependencies. Copy out the gl texture
6426 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6427 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6428 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6430 const GlPixelFormatDesc
*glDesc
;
6431 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6432 char *mem
, *bits
= (char *)rect
.pBits
;
6433 GLint intfmt
= glDesc
->glInternal
;
6434 GLint format
= glDesc
->glFormat
;
6435 GLint type
= glDesc
->glType
;
6436 INT height
= This
->cursorHeight
;
6437 INT width
= This
->cursorWidth
;
6438 INT bpp
= tableEntry
->bpp
;
6441 /* Reformat the texture memory (pitch and width can be
6443 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6444 for(i
= 0; i
< height
; i
++)
6445 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6446 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6449 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6450 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6451 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6454 /* Make sure that a proper texture unit is selected */
6455 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6456 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6457 checkGLcall("glActiveTextureARB");
6459 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
6460 /* Create a new cursor texture */
6461 glGenTextures(1, &This
->cursorTexture
);
6462 checkGLcall("glGenTextures");
6463 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6464 checkGLcall("glBindTexture");
6465 /* Copy the bitmap memory into the cursor texture */
6466 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6467 HeapFree(GetProcessHeap(), 0, mem
);
6468 checkGLcall("glTexImage2D");
6470 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6471 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6472 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6479 FIXME("A cursor texture was not returned.\n");
6480 This
->cursorTexture
= 0;
6485 /* Draw a hardware cursor */
6486 ICONINFO cursorInfo
;
6488 /* Create and clear maskBits because it is not needed for
6489 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6491 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6492 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6493 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6494 WINED3DLOCK_NO_DIRTY_UPDATE
|
6495 WINED3DLOCK_READONLY
6497 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6498 pSur
->currentDesc
.Height
);
6500 cursorInfo
.fIcon
= FALSE
;
6501 cursorInfo
.xHotspot
= XHotSpot
;
6502 cursorInfo
.yHotspot
= YHotSpot
;
6503 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6504 pSur
->currentDesc
.Height
, 1,
6506 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6507 pSur
->currentDesc
.Height
, 1,
6508 32, lockedRect
.pBits
);
6509 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6510 /* Create our cursor and clean up. */
6511 cursor
= CreateIconIndirect(&cursorInfo
);
6513 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6514 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6515 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6516 This
->hardwareCursor
= cursor
;
6517 HeapFree(GetProcessHeap(), 0, maskBits
);
6521 This
->xHotSpot
= XHotSpot
;
6522 This
->yHotSpot
= YHotSpot
;
6526 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6527 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6528 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6530 This
->xScreenSpace
= XScreenSpace
;
6531 This
->yScreenSpace
= YScreenSpace
;
6537 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6538 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6539 BOOL oldVisible
= This
->bCursorVisible
;
6542 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6545 * When ShowCursor is first called it should make the cursor appear at the OS's last
6546 * known cursor position. Because of this, some applications just repetitively call
6547 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6550 This
->xScreenSpace
= pt
.x
;
6551 This
->yScreenSpace
= pt
.y
;
6553 if (This
->haveHardwareCursor
) {
6554 This
->bCursorVisible
= bShow
;
6556 SetCursor(This
->hardwareCursor
);
6562 if (This
->cursorTexture
)
6563 This
->bCursorVisible
= bShow
;
6569 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6571 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6572 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6573 switch (This
->state
) {
6576 case WINED3DERR_DEVICELOST
:
6578 ResourceList
*resourceList
= This
->resources
;
6579 while (NULL
!= resourceList
) {
6580 if (((IWineD3DResourceImpl
*)resourceList
->resource
)->resource
.pool
== WINED3DPOOL_DEFAULT
/* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6581 return WINED3DERR_DEVICENOTRESET
;
6582 resourceList
= resourceList
->next
;
6584 return WINED3DERR_DEVICELOST
;
6586 case WINED3DERR_DRIVERINTERNALERROR
:
6587 return WINED3DERR_DRIVERINTERNALERROR
;
6591 return WINED3DERR_DRIVERINTERNALERROR
;
6595 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6596 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6597 /** FIXME: Resource tracking needs to be done,
6598 * The closes we can do to this is set the priorities of all managed textures low
6599 * and then reset them.
6600 ***********************************************************/
6601 FIXME("(%p) : stub\n", This
);
6605 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6606 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6608 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6609 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6610 /* Release the DC */
6611 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6612 DeleteDC(surface
->hDC
);
6613 /* Release the DIB section */
6614 DeleteObject(surface
->dib
.DIBsection
);
6615 surface
->dib
.bitmap_data
= NULL
;
6616 surface
->resource
.allocatedMemory
= NULL
;
6617 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6619 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6620 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6621 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
6622 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6623 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6625 surface
->pow2Width
= surface
->pow2Height
= 1;
6626 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6627 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6629 if(surface
->glDescription
.textureName
) {
6630 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6632 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6634 surface
->glDescription
.textureName
= 0;
6635 surface
->Flags
&= ~SFLAG_CLIENT
;
6637 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6638 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6639 surface
->Flags
|= SFLAG_NONPOW2
;
6641 surface
->Flags
&= ~SFLAG_NONPOW2
;
6643 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
6644 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6647 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6648 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6649 IWineD3DSwapChainImpl
*swapchain
;
6651 BOOL DisplayModeChanged
= FALSE
;
6652 WINED3DDISPLAYMODE mode
;
6653 TRACE("(%p)\n", This
);
6655 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6657 ERR("Failed to get the first implicit swapchain\n");
6661 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6662 * on an existing gl context, so there's no real need for recreation.
6664 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6666 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6668 TRACE("New params:\n");
6669 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6670 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6671 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6672 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6673 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6674 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6675 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6676 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6677 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6678 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6679 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6680 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6681 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6683 /* No special treatment of these parameters. Just store them */
6684 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6685 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6686 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6687 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6689 /* What to do about these? */
6690 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6691 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6692 ERR("Cannot change the back buffer count yet\n");
6694 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6695 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6696 ERR("Cannot change the back buffer format yet\n");
6698 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6699 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6700 ERR("Cannot change the device window yet\n");
6702 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
6703 ERR("What do do about a changed auto depth stencil parameter?\n");
6706 if(pPresentationParameters
->Windowed
) {
6707 mode
.Width
= swapchain
->orig_width
;
6708 mode
.Height
= swapchain
->orig_height
;
6709 mode
.RefreshRate
= 0;
6710 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6712 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6713 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6714 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6715 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6718 /* Should Width == 800 && Height == 0 set 800x600? */
6719 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6720 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6721 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6728 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
6729 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
6733 if(!pPresentationParameters
->Windowed
) {
6734 DisplayModeChanged
= TRUE
;
6736 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6737 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6739 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6740 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6741 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6744 /* Now set the new viewport */
6745 IWineD3DDevice_SetViewport(iface
, &vp
);
6748 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6749 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6750 DisplayModeChanged
) {
6752 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6753 if(!pPresentationParameters
->Windowed
) {
6754 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
6757 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6759 /* Switching out of fullscreen mode? First set the original res, then change the window */
6760 if(pPresentationParameters
->Windowed
) {
6761 IWineD3DDevice_SetFullscreen(iface
, FALSE
);
6763 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6766 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6770 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6771 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6772 /** FIXME: always true at the moment **/
6773 if(!bEnableDialogs
) {
6774 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6780 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6781 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6782 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6784 *pParameters
= This
->createParms
;
6788 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6789 IWineD3DSwapChain
*swapchain
;
6790 HRESULT hrc
= WINED3D_OK
;
6792 TRACE("Relaying to swapchain\n");
6794 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6795 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
6796 IWineD3DSwapChain_Release(swapchain
);
6801 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6802 IWineD3DSwapChain
*swapchain
;
6803 HRESULT hrc
= WINED3D_OK
;
6805 TRACE("Relaying to swapchain\n");
6807 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6808 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6809 IWineD3DSwapChain_Release(swapchain
);
6815 /** ********************************************************
6816 * Notification functions
6817 ** ********************************************************/
6818 /** This function must be called in the release of a resource when ref == 0,
6819 * the contents of resource must still be correct,
6820 * any handels to other resource held by the caller must be closed
6821 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6822 *****************************************************/
6823 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6824 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6825 ResourceList
* resourceList
;
6827 TRACE("(%p) : resource %p\n", This
, resource
);
6828 /* add a new texture to the frot of the linked list */
6829 resourceList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ResourceList
));
6830 resourceList
->resource
= resource
;
6832 /* Get the old head */
6833 resourceList
->next
= This
->resources
;
6835 This
->resources
= resourceList
;
6836 TRACE("Added resource %p with element %p pointing to %p\n", resource
, resourceList
, resourceList
->next
);
6841 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6842 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6843 ResourceList
* resourceList
= NULL
;
6844 ResourceList
* previousResourceList
= NULL
;
6846 TRACE("(%p) : resource %p\n", This
, resource
);
6848 resourceList
= This
->resources
;
6850 while (resourceList
!= NULL
) {
6851 if(resourceList
->resource
== resource
) break;
6852 previousResourceList
= resourceList
;
6853 resourceList
= resourceList
->next
;
6856 if (resourceList
== NULL
) {
6857 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource
);
6860 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList
->resource
, resourceList
, resourceList
->next
, previousResourceList
);
6862 /* make sure we don't leave a hole in the list */
6863 if (previousResourceList
!= NULL
) {
6864 previousResourceList
->next
= resourceList
->next
;
6866 This
->resources
= resourceList
->next
;
6873 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6874 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6877 TRACE("(%p) : resource %p\n", This
, resource
);
6878 switch(IWineD3DResource_GetType(resource
)){
6879 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6880 case WINED3DRTYPE_SURFACE
: {
6883 /* Cleanup any FBO attachments if d3d is enabled */
6884 if(This
->d3d_initialized
) {
6885 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
6886 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
6888 TRACE("Last active render target destroyed\n");
6889 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6890 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6891 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6892 * and the lastActiveRenderTarget member shouldn't matter
6895 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
6896 TRACE("Activating primary back buffer\n");
6897 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
6898 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
6899 /* Single buffering environment */
6900 TRACE("Activating primary front buffer\n");
6901 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
6903 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6904 /* Implicit render target destroyed, that means the device is being destroyed
6905 * whatever we set here, it shouldn't matter
6907 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
6910 /* May happen during ddraw uninitialization */
6911 TRACE("Render target set, but swapchain does not exist!\n");
6912 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
6916 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6917 if (This
->fbo_color_attachments
[i
] == (IWineD3DSurface
*)resource
) {
6918 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6919 set_render_target_fbo(iface
, i
, NULL
);
6920 This
->fbo_color_attachments
[i
] = NULL
;
6923 if (This
->fbo_depth_attachment
== (IWineD3DSurface
*)resource
) {
6924 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6925 set_depth_stencil_fbo(iface
, NULL
);
6926 This
->fbo_depth_attachment
= NULL
;
6932 case WINED3DRTYPE_TEXTURE
:
6933 case WINED3DRTYPE_CUBETEXTURE
:
6934 case WINED3DRTYPE_VOLUMETEXTURE
:
6935 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6936 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6937 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6938 This
->stateBlock
->textures
[counter
] = NULL
;
6940 if (This
->updateStateBlock
!= This
->stateBlock
){
6941 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6942 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6943 This
->updateStateBlock
->textures
[counter
] = NULL
;
6948 case WINED3DRTYPE_VOLUME
:
6949 /* TODO: nothing really? */
6951 case WINED3DRTYPE_VERTEXBUFFER
:
6952 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6955 TRACE("Cleaning up stream pointers\n");
6957 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6958 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6959 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6961 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6962 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6963 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6964 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6965 /* Set changed flag? */
6968 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) */
6969 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6970 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6971 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6974 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6975 else { /* This shouldn't happen */
6976 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6983 case WINED3DRTYPE_INDEXBUFFER
:
6984 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6985 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6986 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
6987 This
->updateStateBlock
->pIndexData
= NULL
;
6990 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6991 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
6992 This
->stateBlock
->pIndexData
= NULL
;
6998 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7003 /* Remove the resoruce from the resourceStore */
7004 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7006 TRACE("Resource released\n");
7010 /**********************************************************
7011 * IWineD3DDevice VTbl follows
7012 **********************************************************/
7014 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7016 /*** IUnknown methods ***/
7017 IWineD3DDeviceImpl_QueryInterface
,
7018 IWineD3DDeviceImpl_AddRef
,
7019 IWineD3DDeviceImpl_Release
,
7020 /*** IWineD3DDevice methods ***/
7021 IWineD3DDeviceImpl_GetParent
,
7022 /*** Creation methods**/
7023 IWineD3DDeviceImpl_CreateVertexBuffer
,
7024 IWineD3DDeviceImpl_CreateIndexBuffer
,
7025 IWineD3DDeviceImpl_CreateStateBlock
,
7026 IWineD3DDeviceImpl_CreateSurface
,
7027 IWineD3DDeviceImpl_CreateTexture
,
7028 IWineD3DDeviceImpl_CreateVolumeTexture
,
7029 IWineD3DDeviceImpl_CreateVolume
,
7030 IWineD3DDeviceImpl_CreateCubeTexture
,
7031 IWineD3DDeviceImpl_CreateQuery
,
7032 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7033 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7034 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7035 IWineD3DDeviceImpl_CreateVertexShader
,
7036 IWineD3DDeviceImpl_CreatePixelShader
,
7037 IWineD3DDeviceImpl_CreatePalette
,
7038 /*** Odd functions **/
7039 IWineD3DDeviceImpl_Init3D
,
7040 IWineD3DDeviceImpl_Uninit3D
,
7041 IWineD3DDeviceImpl_SetFullscreen
,
7042 IWineD3DDeviceImpl_SetMultithreaded
,
7043 IWineD3DDeviceImpl_EvictManagedResources
,
7044 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7045 IWineD3DDeviceImpl_GetBackBuffer
,
7046 IWineD3DDeviceImpl_GetCreationParameters
,
7047 IWineD3DDeviceImpl_GetDeviceCaps
,
7048 IWineD3DDeviceImpl_GetDirect3D
,
7049 IWineD3DDeviceImpl_GetDisplayMode
,
7050 IWineD3DDeviceImpl_SetDisplayMode
,
7051 IWineD3DDeviceImpl_GetHWND
,
7052 IWineD3DDeviceImpl_SetHWND
,
7053 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7054 IWineD3DDeviceImpl_GetRasterStatus
,
7055 IWineD3DDeviceImpl_GetSwapChain
,
7056 IWineD3DDeviceImpl_Reset
,
7057 IWineD3DDeviceImpl_SetDialogBoxMode
,
7058 IWineD3DDeviceImpl_SetCursorProperties
,
7059 IWineD3DDeviceImpl_SetCursorPosition
,
7060 IWineD3DDeviceImpl_ShowCursor
,
7061 IWineD3DDeviceImpl_TestCooperativeLevel
,
7062 /*** Getters and setters **/
7063 IWineD3DDeviceImpl_SetClipPlane
,
7064 IWineD3DDeviceImpl_GetClipPlane
,
7065 IWineD3DDeviceImpl_SetClipStatus
,
7066 IWineD3DDeviceImpl_GetClipStatus
,
7067 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7068 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7069 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7070 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7071 IWineD3DDeviceImpl_SetFVF
,
7072 IWineD3DDeviceImpl_GetFVF
,
7073 IWineD3DDeviceImpl_SetGammaRamp
,
7074 IWineD3DDeviceImpl_GetGammaRamp
,
7075 IWineD3DDeviceImpl_SetIndices
,
7076 IWineD3DDeviceImpl_GetIndices
,
7077 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7078 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7079 IWineD3DDeviceImpl_SetLight
,
7080 IWineD3DDeviceImpl_GetLight
,
7081 IWineD3DDeviceImpl_SetLightEnable
,
7082 IWineD3DDeviceImpl_GetLightEnable
,
7083 IWineD3DDeviceImpl_SetMaterial
,
7084 IWineD3DDeviceImpl_GetMaterial
,
7085 IWineD3DDeviceImpl_SetNPatchMode
,
7086 IWineD3DDeviceImpl_GetNPatchMode
,
7087 IWineD3DDeviceImpl_SetPaletteEntries
,
7088 IWineD3DDeviceImpl_GetPaletteEntries
,
7089 IWineD3DDeviceImpl_SetPixelShader
,
7090 IWineD3DDeviceImpl_GetPixelShader
,
7091 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7092 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7093 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7094 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7095 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7096 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7097 IWineD3DDeviceImpl_SetRenderState
,
7098 IWineD3DDeviceImpl_GetRenderState
,
7099 IWineD3DDeviceImpl_SetRenderTarget
,
7100 IWineD3DDeviceImpl_GetRenderTarget
,
7101 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7102 IWineD3DDeviceImpl_SetSamplerState
,
7103 IWineD3DDeviceImpl_GetSamplerState
,
7104 IWineD3DDeviceImpl_SetScissorRect
,
7105 IWineD3DDeviceImpl_GetScissorRect
,
7106 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7107 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7108 IWineD3DDeviceImpl_SetStreamSource
,
7109 IWineD3DDeviceImpl_GetStreamSource
,
7110 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7111 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7112 IWineD3DDeviceImpl_SetTexture
,
7113 IWineD3DDeviceImpl_GetTexture
,
7114 IWineD3DDeviceImpl_SetTextureStageState
,
7115 IWineD3DDeviceImpl_GetTextureStageState
,
7116 IWineD3DDeviceImpl_SetTransform
,
7117 IWineD3DDeviceImpl_GetTransform
,
7118 IWineD3DDeviceImpl_SetVertexDeclaration
,
7119 IWineD3DDeviceImpl_GetVertexDeclaration
,
7120 IWineD3DDeviceImpl_SetVertexShader
,
7121 IWineD3DDeviceImpl_GetVertexShader
,
7122 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7123 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7124 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7125 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7126 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7127 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7128 IWineD3DDeviceImpl_SetViewport
,
7129 IWineD3DDeviceImpl_GetViewport
,
7130 IWineD3DDeviceImpl_MultiplyTransform
,
7131 IWineD3DDeviceImpl_ValidateDevice
,
7132 IWineD3DDeviceImpl_ProcessVertices
,
7133 /*** State block ***/
7134 IWineD3DDeviceImpl_BeginStateBlock
,
7135 IWineD3DDeviceImpl_EndStateBlock
,
7136 /*** Scene management ***/
7137 IWineD3DDeviceImpl_BeginScene
,
7138 IWineD3DDeviceImpl_EndScene
,
7139 IWineD3DDeviceImpl_Present
,
7140 IWineD3DDeviceImpl_Clear
,
7142 IWineD3DDeviceImpl_DrawPrimitive
,
7143 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7144 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7145 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7146 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7147 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7148 IWineD3DDeviceImpl_DrawRectPatch
,
7149 IWineD3DDeviceImpl_DrawTriPatch
,
7150 IWineD3DDeviceImpl_DeletePatch
,
7151 IWineD3DDeviceImpl_ColorFill
,
7152 IWineD3DDeviceImpl_UpdateTexture
,
7153 IWineD3DDeviceImpl_UpdateSurface
,
7154 IWineD3DDeviceImpl_GetFrontBufferData
,
7155 /*** object tracking ***/
7156 IWineD3DDeviceImpl_ResourceReleased
7160 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7161 WINED3DRS_ALPHABLENDENABLE
,
7162 WINED3DRS_ALPHAFUNC
,
7163 WINED3DRS_ALPHAREF
,
7164 WINED3DRS_ALPHATESTENABLE
,
7166 WINED3DRS_COLORWRITEENABLE
,
7167 WINED3DRS_DESTBLEND
,
7168 WINED3DRS_DITHERENABLE
,
7169 WINED3DRS_FILLMODE
,
7170 WINED3DRS_FOGDENSITY
,
7172 WINED3DRS_FOGSTART
,
7173 WINED3DRS_LASTPIXEL
,
7174 WINED3DRS_SHADEMODE
,
7175 WINED3DRS_SRCBLEND
,
7176 WINED3DRS_STENCILENABLE
,
7177 WINED3DRS_STENCILFAIL
,
7178 WINED3DRS_STENCILFUNC
,
7179 WINED3DRS_STENCILMASK
,
7180 WINED3DRS_STENCILPASS
,
7181 WINED3DRS_STENCILREF
,
7182 WINED3DRS_STENCILWRITEMASK
,
7183 WINED3DRS_STENCILZFAIL
,
7184 WINED3DRS_TEXTUREFACTOR
,
7195 WINED3DRS_ZWRITEENABLE
7198 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7199 WINED3DTSS_ADDRESSW
,
7200 WINED3DTSS_ALPHAARG0
,
7201 WINED3DTSS_ALPHAARG1
,
7202 WINED3DTSS_ALPHAARG2
,
7203 WINED3DTSS_ALPHAOP
,
7204 WINED3DTSS_BUMPENVLOFFSET
,
7205 WINED3DTSS_BUMPENVLSCALE
,
7206 WINED3DTSS_BUMPENVMAT00
,
7207 WINED3DTSS_BUMPENVMAT01
,
7208 WINED3DTSS_BUMPENVMAT10
,
7209 WINED3DTSS_BUMPENVMAT11
,
7210 WINED3DTSS_COLORARG0
,
7211 WINED3DTSS_COLORARG1
,
7212 WINED3DTSS_COLORARG2
,
7213 WINED3DTSS_COLOROP
,
7214 WINED3DTSS_RESULTARG
,
7215 WINED3DTSS_TEXCOORDINDEX
,
7216 WINED3DTSS_TEXTURETRANSFORMFLAGS
7219 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7220 WINED3DSAMP_ADDRESSU
,
7221 WINED3DSAMP_ADDRESSV
,
7222 WINED3DSAMP_ADDRESSW
,
7223 WINED3DSAMP_BORDERCOLOR
,
7224 WINED3DSAMP_MAGFILTER
,
7225 WINED3DSAMP_MINFILTER
,
7226 WINED3DSAMP_MIPFILTER
,
7227 WINED3DSAMP_MIPMAPLODBIAS
,
7228 WINED3DSAMP_MAXMIPLEVEL
,
7229 WINED3DSAMP_MAXANISOTROPY
,
7230 WINED3DSAMP_SRGBTEXTURE
,
7231 WINED3DSAMP_ELEMENTINDEX
7234 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7236 WINED3DRS_AMBIENTMATERIALSOURCE
,
7237 WINED3DRS_CLIPPING
,
7238 WINED3DRS_CLIPPLANEENABLE
,
7239 WINED3DRS_COLORVERTEX
,
7240 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7241 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7242 WINED3DRS_FOGDENSITY
,
7244 WINED3DRS_FOGSTART
,
7245 WINED3DRS_FOGTABLEMODE
,
7246 WINED3DRS_FOGVERTEXMODE
,
7247 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7248 WINED3DRS_LIGHTING
,
7249 WINED3DRS_LOCALVIEWER
,
7250 WINED3DRS_MULTISAMPLEANTIALIAS
,
7251 WINED3DRS_MULTISAMPLEMASK
,
7252 WINED3DRS_NORMALIZENORMALS
,
7253 WINED3DRS_PATCHEDGESTYLE
,
7254 WINED3DRS_POINTSCALE_A
,
7255 WINED3DRS_POINTSCALE_B
,
7256 WINED3DRS_POINTSCALE_C
,
7257 WINED3DRS_POINTSCALEENABLE
,
7258 WINED3DRS_POINTSIZE
,
7259 WINED3DRS_POINTSIZE_MAX
,
7260 WINED3DRS_POINTSIZE_MIN
,
7261 WINED3DRS_POINTSPRITEENABLE
,
7262 WINED3DRS_RANGEFOGENABLE
,
7263 WINED3DRS_SPECULARMATERIALSOURCE
,
7264 WINED3DRS_TWEENFACTOR
,
7265 WINED3DRS_VERTEXBLEND
,
7266 WINED3DRS_CULLMODE
,
7270 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7271 WINED3DTSS_TEXCOORDINDEX
,
7272 WINED3DTSS_TEXTURETRANSFORMFLAGS
7275 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7276 WINED3DSAMP_DMAPOFFSET
7279 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7280 DWORD rep
= StateTable
[state
].representative
;
7284 WineD3DContext
*context
;
7287 for(i
= 0; i
< This
->numContexts
; i
++) {
7288 context
= This
->contexts
[i
];
7289 if(isStateDirty(context
, rep
)) continue;
7291 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7294 context
->isStateDirty
[idx
] |= (1 << shift
);