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.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
136 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
138 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
139 if (IsEqualGUID(riid
, &IID_IUnknown
)
140 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
141 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
142 IUnknown_AddRef(iface
);
147 return E_NOINTERFACE
;
150 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
151 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
152 ULONG refCount
= InterlockedIncrement(&This
->ref
);
154 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
158 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
159 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
160 ULONG refCount
= InterlockedDecrement(&This
->ref
);
162 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->src_fbo
));
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->dst_fbo
));
175 if (This
->glsl_program_lookup
) hash_table_destroy(This
->glsl_program_lookup
);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This
->resources
!= NULL
) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
183 dumpResources(This
->resources
);
186 if(This
->contexts
) ERR("Context array not freed!\n");
187 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
188 This
->haveHardwareCursor
= FALSE
;
190 IWineD3D_Release(This
->wineD3D
);
191 This
->wineD3D
= NULL
;
192 HeapFree(GetProcessHeap(), 0, This
);
193 TRACE("Freed device %p\n", This
);
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
203 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
204 *pParent
= This
->parent
;
205 IUnknown_AddRef(This
->parent
);
209 static void CreateVBO(IWineD3DVertexBufferImpl
*object
) {
210 IWineD3DDeviceImpl
*This
= object
->resource
.wineD3DDevice
; /* Needed for GL_EXTCALL */
211 GLenum error
, glUsage
;
212 DWORD vboUsage
= object
->resource
.usage
;
213 if(object
->Flags
& VBFLAG_VBOCREATEFAIL
) {
214 WARN("Creating a vbo failed once, not trying again\n");
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object
, debug_d3dusage(vboUsage
));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR
);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
239 error
= glGetError();
240 if(object
->vbo
== 0 || error
!= GL_NO_ERROR
) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error
), error
);
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, object
->vbo
));
246 error
= glGetError();
247 if(error
!= GL_NO_ERROR
) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error
), error
);
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage
& (WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
) ) {
257 case WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
:
258 case WINED3DUSAGE_DYNAMIC
:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage
= GL_STREAM_DRAW_ARB
;
262 case WINED3DUSAGE_WRITEONLY
:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage
= GL_DYNAMIC_DRAW_ARB
;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
274 error
= glGetError();
275 if(error
!= GL_NO_ERROR
) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error
), error
);
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
288 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
293 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
294 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
296 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
297 IWineD3DVertexBufferImpl
*object
;
298 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
299 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer
= NULL
;
305 return WINED3DERR_INVALIDCALL
;
308 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
311 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
313 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
314 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->resource
.size
);
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
) && Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) &&
335 (dxVersion
> 7 || !conv
) ) {
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
342 GLenum error
, glUsage
;
343 TRACE("Creating VBO for Index Buffer %p\n", object
);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
356 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
357 error
= glGetError();
358 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
364 error
= glGetError();
365 if(error
!= GL_NO_ERROR
) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage
= GL_STATIC_DRAW_ARB
;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
375 error
= glGetError();
376 if(error
!= GL_NO_ERROR
) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
391 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
392 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
393 HANDLE
*sharedHandle
, IUnknown
*parent
) {
394 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
395 IWineD3DIndexBufferImpl
*object
;
396 TRACE("(%p) Creating index buffer\n", This
);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
401 if (Pool
== WINED3DPOOL_DEFAULT
) { /* We need a local copy for drawStridedSlow */
402 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,object
->resource
.size
);
405 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
406 CreateIndexBufferVBO(This
, object
);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
410 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
411 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
416 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
418 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
419 IWineD3DStateBlockImpl
*object
;
423 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
424 object
->blockType
= Type
;
426 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
427 list_init(&object
->lightMap
[i
]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type
== WINED3DSBT_INIT
) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
438 temp_result
= allocate_shader_constants(object
);
439 if (WINED3D_OK
!= temp_result
)
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This
->stateBlock
!= NULL
)
444 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
446 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
448 /* Reset the ref and type after kludging it */
449 object
->wineD3DDevice
= This
;
451 object
->blockType
= Type
;
453 TRACE("Updating changed flags appropriate for type %d\n", Type
);
455 if (Type
== WINED3DSBT_ALL
) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
460 /* Lights are not part of the changed / set structure */
461 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
463 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
464 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
465 light
->changed
= TRUE
;
466 light
->enabledChanged
= TRUE
;
469 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
470 object
->contained_render_states
[j
- 1] = j
;
472 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
475 object
->contained_transform_states
[j
- 1] = j
;
477 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
478 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
479 object
->contained_vs_consts_f
[j
] = j
;
481 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
482 for(j
= 0; j
< MAX_CONST_I
; j
++) {
483 object
->contained_vs_consts_i
[j
] = j
;
485 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
486 for(j
= 0; j
< MAX_CONST_B
; j
++) {
487 object
->contained_vs_consts_b
[j
] = j
;
489 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
490 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
491 object
->contained_ps_consts_f
[j
] = j
;
493 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
494 for(j
= 0; j
< MAX_CONST_I
; j
++) {
495 object
->contained_ps_consts_i
[j
] = j
;
497 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
498 for(j
= 0; j
< MAX_CONST_B
; j
++) {
499 object
->contained_ps_consts_b
[j
] = j
;
501 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
502 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
503 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
504 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
505 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
506 object
->num_contained_tss_states
++;
509 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
510 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
511 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
512 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
513 object
->num_contained_sampler_states
++;
517 for(i
= 0; i
< MAX_STREAMS
; i
++) {
518 if(object
->streamSource
[i
]) {
519 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
522 if(object
->pIndexData
) {
523 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
525 if(object
->vertexShader
) {
526 IWineD3DVertexShader_AddRef(object
->vertexShader
);
528 if(object
->pixelShader
) {
529 IWineD3DPixelShader_AddRef(object
->pixelShader
);
532 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
537 object
->changed
.pixelShader
= TRUE
;
539 /* Pixel Shader Constants */
540 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
541 object
->contained_ps_consts_f
[i
] = i
;
542 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
544 object
->num_contained_ps_consts_f
= GL_LIMITS(vshader_constantsF
);
545 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
546 object
->contained_ps_consts_b
[i
] = i
;
547 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
549 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
550 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
551 object
->contained_ps_consts_i
[i
] = i
;
552 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
554 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
556 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
557 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
558 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
560 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
561 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
562 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
563 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
564 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
565 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
566 object
->num_contained_tss_states
++;
569 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
570 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
571 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
572 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
573 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
574 object
->num_contained_sampler_states
++;
577 if(object
->pixelShader
) {
578 IWineD3DPixelShader_AddRef(object
->pixelShader
);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i
= 0; i
< MAX_STREAMS
; i
++) {
585 object
->streamSource
[i
] = NULL
;
587 object
->pIndexData
= NULL
;
588 object
->vertexShader
= NULL
;
590 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
595 object
->changed
.vertexShader
= TRUE
;
597 /* Vertex Shader Constants */
598 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
599 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
600 object
->contained_vs_consts_f
[i
] = i
;
602 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
603 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
604 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
605 object
->contained_vs_consts_b
[i
] = i
;
607 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
608 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
609 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
610 object
->contained_vs_consts_i
[i
] = i
;
612 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
613 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
614 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
615 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
617 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
618 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
619 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
620 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
621 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
622 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
623 object
->num_contained_tss_states
++;
626 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
627 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
628 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
629 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
630 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
631 object
->num_contained_sampler_states
++;
635 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
637 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
638 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
639 light
->changed
= TRUE
;
640 light
->enabledChanged
= TRUE
;
644 for(i
= 0; i
< MAX_STREAMS
; i
++) {
645 if(object
->streamSource
[i
]) {
646 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
649 if(object
->vertexShader
) {
650 IWineD3DVertexShader_AddRef(object
->vertexShader
);
652 object
->pIndexData
= NULL
;
653 object
->pixelShader
= NULL
;
655 FIXME("Unrecognized state block type %d\n", Type
);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
662 /* ************************************
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 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.
671 ******************************** */
673 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
) {
674 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
675 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size
= 1;
677 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, NULL
, NULL
);
678 TRACE("(%p) Create surface\n",This
);
680 /** FIXME: Check ranges on the inputs are valid
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
688 *******************************/
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality
< 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
704 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
707 if(MultisampleQuality
> 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
709 MultisampleQuality
=0;
712 /** FIXME: Check that the format is supported
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
719 *********************************/
720 if (WINED3DFMT_UNKNOWN
== Format
) {
722 } else if (Format
== WINED3DFMT_DXT1
) {
723 /* DXT1 is half byte per pixel */
724 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
726 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
727 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
728 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
730 /* The pitch is a multiple of 4 bytes */
731 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
740 object
->currentDesc
.Width
= Width
;
741 object
->currentDesc
.Height
= Height
;
742 object
->currentDesc
.MultiSampleType
= MultiSample
;
743 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
744 object
->glDescription
.level
= Level
;
748 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
749 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
750 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
753 if (WINED3DFMT_UNKNOWN
!= Format
) {
754 object
->bytesPerPixel
= tableEntry
->bpp
;
756 object
->bytesPerPixel
= 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
768 case WINED3DPOOL_SCRATCH
:
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
774 case WINED3DPOOL_SYSTEMMEM
:
775 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED
:
778 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
782 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
784 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
788 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
792 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
800 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
804 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
806 /* Look at the implementation and set the correct Vtable */
809 /* Check if a 3D adapter is available when creating gl surfaces */
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
813 HeapFree(GetProcessHeap(), 0, object
);
814 return WINED3DERR_NOTAVAILABLE
;
819 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl
);
825 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
826 return WINED3DERR_INVALIDCALL
;
829 list_init(&object
->renderbuffers
);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
836 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
837 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
838 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
841 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
842 IWineD3DTextureImpl
*object
;
847 unsigned int pow2Width
;
848 unsigned int pow2Height
;
849 const GlPixelFormatDesc
*glDesc
;
850 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
853 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
854 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
855 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
857 /* TODO: It should only be possible to create textures for formats
858 that are reported as supported */
859 if (WINED3DFMT_UNKNOWN
>= Format
) {
860 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
861 return WINED3DERR_INVALIDCALL
;
864 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
865 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
866 object
->width
= Width
;
867 object
->height
= Height
;
869 /** Non-power2 support **/
870 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
874 /* Find the nearest pow2 match */
875 pow2Width
= pow2Height
= 1;
876 while (pow2Width
< Width
) pow2Width
<<= 1;
877 while (pow2Height
< Height
) pow2Height
<<= 1;
880 /** FIXME: add support for real non-power-two if it's provided by the video card **/
881 /* Precalculated scaling for 'faked' non power of two texture coords */
882 object
->pow2scalingFactorX
= (((float)Width
) / ((float)pow2Width
));
883 object
->pow2scalingFactorY
= (((float)Height
) / ((float)pow2Height
));
884 TRACE(" xf(%f) yf(%f)\n", object
->pow2scalingFactorX
, object
->pow2scalingFactorY
);
886 /* Calculate levels for mip mapping */
887 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
888 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
889 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
890 return WINED3DERR_INVALIDCALL
;
893 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
894 return WINED3DERR_INVALIDCALL
;
896 object
->baseTexture
.levels
= 1;
897 } else if (Levels
== 0) {
898 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
899 object
->baseTexture
.levels
++;
902 while (tmpW
> 1 || tmpH
> 1) {
903 tmpW
= max(1, tmpW
>> 1);
904 tmpH
= max(1, tmpH
>> 1);
905 object
->baseTexture
.levels
++;
907 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
910 /* Generate all the surfaces */
913 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
915 /* use the callback to create the texture surface */
916 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
917 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
918 FIXME("Failed to create surface %p\n", object
);
920 object
->surfaces
[i
] = NULL
;
921 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
927 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
928 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
929 /* calculate the next mipmap level */
930 tmpW
= max(1, tmpW
>> 1);
931 tmpH
= max(1, tmpH
>> 1);
933 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
935 TRACE("(%p) : Created texture %p\n", This
, object
);
939 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
940 UINT Width
, UINT Height
, UINT Depth
,
941 UINT Levels
, DWORD Usage
,
942 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
943 IWineD3DVolumeTexture
**ppVolumeTexture
,
944 HANDLE
*pSharedHandle
, IUnknown
*parent
,
945 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
947 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
948 IWineD3DVolumeTextureImpl
*object
;
953 const GlPixelFormatDesc
*glDesc
;
954 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
956 /* TODO: It should only be possible to create textures for formats
957 that are reported as supported */
958 if (WINED3DFMT_UNKNOWN
>= Format
) {
959 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
960 return WINED3DERR_INVALIDCALL
;
963 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
964 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
966 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
967 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
969 object
->width
= Width
;
970 object
->height
= Height
;
971 object
->depth
= Depth
;
973 /* Calculate levels for mip mapping */
974 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
975 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
976 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
977 return WINED3DERR_INVALIDCALL
;
980 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
981 return WINED3DERR_INVALIDCALL
;
984 } else if (Levels
== 0) {
985 object
->baseTexture
.levels
++;
989 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
990 tmpW
= max(1, tmpW
>> 1);
991 tmpH
= max(1, tmpH
>> 1);
992 tmpD
= max(1, tmpD
>> 1);
993 object
->baseTexture
.levels
++;
995 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
998 /* Generate all the surfaces */
1003 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1006 /* Create the volume */
1007 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
1008 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
1011 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
1012 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
1013 *ppVolumeTexture
= NULL
;
1017 /* Set its container to this object */
1018 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1020 /* calcualte the next mipmap level */
1021 tmpW
= max(1, tmpW
>> 1);
1022 tmpH
= max(1, tmpH
>> 1);
1023 tmpD
= max(1, tmpD
>> 1);
1025 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1027 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1028 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1032 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1033 UINT Width
, UINT Height
, UINT Depth
,
1035 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1036 IWineD3DVolume
** ppVolume
,
1037 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1040 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1041 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1043 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1045 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1046 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1048 object
->currentDesc
.Width
= Width
;
1049 object
->currentDesc
.Height
= Height
;
1050 object
->currentDesc
.Depth
= Depth
;
1051 object
->bytesPerPixel
= formatDesc
->bpp
;
1053 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1054 object
->lockable
= TRUE
;
1055 object
->locked
= FALSE
;
1056 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1057 object
->dirty
= TRUE
;
1059 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1062 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1063 UINT Levels
, DWORD Usage
,
1064 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1065 IWineD3DCubeTexture
**ppCubeTexture
,
1066 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1067 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1069 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1070 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1074 unsigned int pow2EdgeLength
= EdgeLength
;
1075 const GlPixelFormatDesc
*glDesc
;
1076 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1078 /* TODO: It should only be possible to create textures for formats
1079 that are reported as supported */
1080 if (WINED3DFMT_UNKNOWN
>= Format
) {
1081 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1082 return WINED3DERR_INVALIDCALL
;
1085 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1086 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1087 return WINED3DERR_INVALIDCALL
;
1090 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1091 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1093 TRACE("(%p) Create Cube Texture\n", This
);
1095 /** Non-power2 support **/
1097 /* Find the nearest pow2 match */
1099 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1101 object
->edgeLength
= EdgeLength
;
1102 /* TODO: support for native non-power 2 */
1103 /* Precalculated scaling for 'faked' non power of two texture coords */
1104 object
->pow2scalingFactor
= ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1106 /* Calculate levels for mip mapping */
1107 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1108 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1109 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1110 HeapFree(GetProcessHeap(), 0, object
);
1111 *ppCubeTexture
= NULL
;
1113 return WINED3DERR_INVALIDCALL
;
1116 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1117 HeapFree(GetProcessHeap(), 0, object
);
1118 *ppCubeTexture
= NULL
;
1120 return WINED3DERR_INVALIDCALL
;
1123 } else if (Levels
== 0) {
1124 object
->baseTexture
.levels
++;
1127 tmpW
= max(1, tmpW
>> 1);
1128 object
->baseTexture
.levels
++;
1130 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1133 /* Generate all the surfaces */
1135 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1137 /* Create the 6 faces */
1138 for (j
= 0; j
< 6; j
++) {
1140 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1141 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1143 if(hr
!= WINED3D_OK
) {
1147 for (l
= 0; l
< j
; l
++) {
1148 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1150 for (k
= 0; k
< i
; k
++) {
1151 for (l
= 0; l
< 6; l
++) {
1152 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1156 FIXME("(%p) Failed to create surface\n",object
);
1157 HeapFree(GetProcessHeap(),0,object
);
1158 *ppCubeTexture
= NULL
;
1161 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1162 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1164 tmpW
= max(1, tmpW
>> 1);
1166 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1168 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1169 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1173 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1174 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1175 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1176 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1178 /* Just a check to see if we support this type of query */
1180 case WINED3DQUERYTYPE_OCCLUSION
:
1181 TRACE("(%p) occlusion query\n", This
);
1182 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1185 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1188 case WINED3DQUERYTYPE_EVENT
:
1189 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1190 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1191 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1193 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1198 case WINED3DQUERYTYPE_VCACHE
:
1199 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1200 case WINED3DQUERYTYPE_VERTEXSTATS
:
1201 case WINED3DQUERYTYPE_TIMESTAMP
:
1202 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1203 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1204 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1205 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1206 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1207 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1208 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1209 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1211 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1213 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1217 D3DCREATEOBJECTINSTANCE(object
, Query
)
1218 object
->type
= Type
;
1219 /* allocated the 'extended' data based on the type of query requested */
1221 case WINED3DQUERYTYPE_OCCLUSION
:
1222 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1223 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1224 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1225 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1226 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1229 case WINED3DQUERYTYPE_EVENT
:
1230 if(GL_SUPPORT(APPLE_FENCE
)) {
1231 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1232 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1233 checkGLcall("glGenFencesAPPLE");
1234 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1235 } else if(GL_SUPPORT(NV_FENCE
)) {
1236 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1237 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1238 checkGLcall("glGenFencesNV");
1239 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1243 case WINED3DQUERYTYPE_VCACHE
:
1244 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1245 case WINED3DQUERYTYPE_VERTEXSTATS
:
1246 case WINED3DQUERYTYPE_TIMESTAMP
:
1247 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1248 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1249 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1250 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1251 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1252 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1253 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1254 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1256 object
->extendedData
= 0;
1257 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1259 TRACE("(%p) : Created Query %p\n", This
, object
);
1263 /*****************************************************************************
1264 * IWineD3DDeviceImpl_SetupFullscreenWindow
1266 * Helper function that modifies a HWND's Style and ExStyle for proper
1270 * iface: Pointer to the IWineD3DDevice interface
1271 * window: Window to setup
1273 *****************************************************************************/
1274 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1275 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1277 LONG style
, exStyle
;
1278 /* Don't do anything if an original style is stored.
1279 * That shouldn't happen
1281 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1282 if (This
->style
|| This
->exStyle
) {
1283 ERR("(%p): Want to change the window parameters of HWND %p, but "
1284 "another style is stored for restoration afterwards\n", This
, window
);
1287 /* Get the parameters and save them */
1288 style
= GetWindowLongW(window
, GWL_STYLE
);
1289 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1290 This
->style
= style
;
1291 This
->exStyle
= exStyle
;
1293 /* Filter out window decorations */
1294 style
&= ~WS_CAPTION
;
1295 style
&= ~WS_THICKFRAME
;
1296 exStyle
&= ~WS_EX_WINDOWEDGE
;
1297 exStyle
&= ~WS_EX_CLIENTEDGE
;
1299 /* Make sure the window is managed, otherwise we won't get keyboard input */
1300 style
|= WS_POPUP
| WS_SYSMENU
;
1302 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1303 This
->style
, This
->exStyle
, style
, exStyle
);
1305 SetWindowLongW(window
, GWL_STYLE
, style
);
1306 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1308 /* Inform the window about the update. */
1309 SetWindowPos(window
, HWND_TOP
, 0, 0,
1310 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1311 ShowWindow(window
, SW_NORMAL
);
1314 /*****************************************************************************
1315 * IWineD3DDeviceImpl_RestoreWindow
1317 * Helper function that restores a windows' properties when taking it out
1318 * of fullscreen mode
1321 * iface: Pointer to the IWineD3DDevice interface
1322 * window: Window to setup
1324 *****************************************************************************/
1325 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1326 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1328 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1329 * switch, do nothing
1331 if (!This
->style
&& !This
->exStyle
) return;
1333 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1334 This
, window
, This
->style
, This
->exStyle
);
1336 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1337 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1339 /* Delete the old values */
1343 /* Inform the window about the update */
1344 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1345 0, 0, 0, 0, /* Pos, Size, ignored */
1346 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1349 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1350 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1352 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1353 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1354 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1357 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1358 HRESULT hr
= WINED3D_OK
;
1359 IUnknown
*bufferParent
;
1361 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1363 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1364 * does a device hold a reference to a swap chain giving them a lifetime of the device
1365 * or does the swap chain notify the device of its destruction.
1366 *******************************/
1368 /* Check the params */
1369 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1370 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1371 return WINED3DERR_INVALIDCALL
;
1372 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1373 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");
1376 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1378 /*********************
1379 * Lookup the window Handle and the relating X window handle
1380 ********************/
1382 /* Setup hwnd we are using, plus which display this equates to */
1383 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1384 if (!object
->win_handle
) {
1385 object
->win_handle
= This
->createParms
.hFocusWindow
;
1388 hDc
= GetDC(object
->win_handle
);
1389 TRACE("Using hDc %p\n", hDc
);
1392 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1393 return WINED3DERR_NOTAVAILABLE
;
1396 object
->orig_width
= GetSystemMetrics(SM_CXSCREEN
);
1397 object
->orig_height
= GetSystemMetrics(SM_CYSCREEN
);
1398 object
->orig_fmt
= pixelformat_for_depth(GetDeviceCaps(hDc
, BITSPIXEL
) * GetDeviceCaps(hDc
, PLANES
));
1399 ReleaseDC(object
->win_handle
, hDc
);
1401 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1402 * then the corresponding dimension of the client area of the hDeviceWindow
1403 * (or the focus window, if hDeviceWindow is NULL) is taken.
1404 **********************/
1406 if (pPresentationParameters
->Windowed
&&
1407 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1408 (pPresentationParameters
->BackBufferHeight
== 0) ||
1409 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1412 GetClientRect(object
->win_handle
, &Rect
);
1414 if (pPresentationParameters
->BackBufferWidth
== 0) {
1415 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1416 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1418 if (pPresentationParameters
->BackBufferHeight
== 0) {
1419 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1420 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1422 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1423 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1424 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1428 /* Put the correct figures in the presentation parameters */
1429 TRACE("Copying across presentation parameters\n");
1430 object
->presentParms
= *pPresentationParameters
;
1432 TRACE("calling rendertarget CB\n");
1433 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1435 object
->presentParms
.BackBufferWidth
,
1436 object
->presentParms
.BackBufferHeight
,
1437 object
->presentParms
.BackBufferFormat
,
1438 object
->presentParms
.MultiSampleType
,
1439 object
->presentParms
.MultiSampleQuality
,
1440 TRUE
/* Lockable */,
1441 &object
->frontBuffer
,
1442 NULL
/* pShared (always null)*/);
1443 if (object
->frontBuffer
!= NULL
) {
1444 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1446 ERR("Failed to create the front buffer\n");
1451 * Create an opengl context for the display visual
1452 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1453 * use different properties after that point in time. FIXME: How to handle when requested format
1454 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1455 * it chooses is identical to the one already being used!
1456 **********************************/
1457 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1459 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1460 if(!object
->context
)
1461 return E_OUTOFMEMORY
;
1462 object
->num_contexts
= 1;
1464 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1465 if (!object
->context
[0]) {
1466 ERR("Failed to create a new context\n");
1467 hr
= WINED3DERR_NOTAVAILABLE
;
1470 TRACE("Context created (HWND=%p, glContext=%p)\n",
1471 object
->win_handle
, object
->context
[0]->glCtx
);
1474 /*********************
1475 * Windowed / Fullscreen
1476 *******************/
1479 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1480 * so we should really check to see if there is a fullscreen swapchain already
1481 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1482 **************************************/
1484 if (!pPresentationParameters
->Windowed
) {
1491 /* Get info on the current display setup */
1493 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1496 /* Change the display settings */
1497 memset(&devmode
, 0, sizeof(devmode
));
1498 devmode
.dmSize
= sizeof(devmode
);
1499 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1500 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1501 devmode
.dmPelsWidth
= pPresentationParameters
->BackBufferWidth
;
1502 devmode
.dmPelsHeight
= pPresentationParameters
->BackBufferHeight
;
1503 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1505 /* For GetDisplayMode */
1506 This
->ddraw_width
= devmode
.dmPelsWidth
;
1507 This
->ddraw_height
= devmode
.dmPelsHeight
;
1508 This
->ddraw_format
= pPresentationParameters
->BackBufferFormat
;
1510 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1512 /* And finally clip mouse to our screen */
1513 SetRect(&clip_rc
, 0, 0, devmode
.dmPelsWidth
, devmode
.dmPelsHeight
);
1514 ClipCursor(&clip_rc
);
1517 /*********************
1518 * Create the back, front and stencil buffers
1519 *******************/
1520 if(object
->presentParms
.BackBufferCount
> 0) {
1523 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1524 if(!object
->backBuffer
) {
1525 ERR("Out of memory\n");
1530 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1531 TRACE("calling rendertarget CB\n");
1532 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1534 object
->presentParms
.BackBufferWidth
,
1535 object
->presentParms
.BackBufferHeight
,
1536 object
->presentParms
.BackBufferFormat
,
1537 object
->presentParms
.MultiSampleType
,
1538 object
->presentParms
.MultiSampleQuality
,
1539 TRUE
/* Lockable */,
1540 &object
->backBuffer
[i
],
1541 NULL
/* pShared (always null)*/);
1542 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1543 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1545 ERR("Cannot create new back buffer\n");
1549 glDrawBuffer(GL_BACK
);
1550 checkGLcall("glDrawBuffer(GL_BACK)");
1554 object
->backBuffer
= NULL
;
1556 /* Single buffering - draw to front buffer */
1558 glDrawBuffer(GL_FRONT
);
1559 checkGLcall("glDrawBuffer(GL_FRONT)");
1563 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1564 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1565 TRACE("Creating depth stencil buffer\n");
1566 if (This
->depthStencilBuffer
== NULL
) {
1567 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1569 object
->presentParms
.BackBufferWidth
,
1570 object
->presentParms
.BackBufferHeight
,
1571 object
->presentParms
.AutoDepthStencilFormat
,
1572 object
->presentParms
.MultiSampleType
,
1573 object
->presentParms
.MultiSampleQuality
,
1574 FALSE
/* FIXME: Discard */,
1575 &This
->depthStencilBuffer
,
1576 NULL
/* pShared (always null)*/ );
1577 if (This
->depthStencilBuffer
!= NULL
)
1578 IWineD3DSurface_SetContainer(This
->depthStencilBuffer
, 0);
1581 /** TODO: A check on width, height and multisample types
1582 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1583 ****************************/
1584 object
->wantsDepthStencilBuffer
= TRUE
;
1586 object
->wantsDepthStencilBuffer
= FALSE
;
1589 TRACE("Created swapchain %p\n", object
);
1590 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1594 if (object
->backBuffer
) {
1596 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1597 if(object
->backBuffer
[i
]) {
1598 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1599 IUnknown_Release(bufferParent
); /* once for the get parent */
1600 if (IUnknown_Release(bufferParent
) > 0) {
1601 FIXME("(%p) Something's still holding the back buffer\n",This
);
1605 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1606 object
->backBuffer
= NULL
;
1608 if(object
->context
[0])
1609 DestroyContext(This
, object
->context
[0]);
1610 if(object
->frontBuffer
) {
1611 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1612 IUnknown_Release(bufferParent
); /* once for the get parent */
1613 if (IUnknown_Release(bufferParent
) > 0) {
1614 FIXME("(%p) Something's still holding the front buffer\n",This
);
1617 HeapFree(GetProcessHeap(), 0, object
);
1621 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1622 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1623 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1624 TRACE("(%p)\n", This
);
1626 return This
->NumberOfSwapChains
;
1629 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1630 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1631 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1633 if(iSwapChain
< This
->NumberOfSwapChains
) {
1634 *pSwapChain
= This
->swapchains
[iSwapChain
];
1635 IWineD3DSwapChain_AddRef(*pSwapChain
);
1636 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1639 TRACE("Swapchain out of range\n");
1641 return WINED3DERR_INVALIDCALL
;
1646 * Vertex Declaration
1648 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1649 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, size_t element_count
) {
1650 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1651 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1652 HRESULT hr
= WINED3D_OK
;
1654 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1655 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1657 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1659 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1664 static size_t ConvertFvfToDeclaration(DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1666 unsigned int idx
, idx2
;
1667 unsigned int offset
;
1668 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1669 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1670 BOOL has_blend_idx
= has_blend
&&
1671 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1672 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1673 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1674 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1675 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1676 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1677 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1679 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1680 DWORD texcoords
= (fvf
& 0x00FF0000) >> 16;
1682 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1683 WINED3DVERTEXELEMENT
*elements
= NULL
;
1686 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1687 if (has_blend_idx
) num_blends
--;
1689 /* Compute declaration size */
1690 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1691 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1693 /* convert the declaration */
1694 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1698 memcpy(&elements
[size
-1], &end_element
, sizeof(WINED3DVERTEXELEMENT
));
1701 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1702 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1703 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1706 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1707 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1709 elements
[idx
].UsageIndex
= 0;
1712 if (has_blend
&& (num_blends
> 0)) {
1713 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1714 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1716 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1717 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1718 elements
[idx
].UsageIndex
= 0;
1721 if (has_blend_idx
) {
1722 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1723 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1724 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1725 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1726 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1728 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1729 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1730 elements
[idx
].UsageIndex
= 0;
1734 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1735 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1736 elements
[idx
].UsageIndex
= 0;
1740 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1741 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1742 elements
[idx
].UsageIndex
= 0;
1746 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1747 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1748 elements
[idx
].UsageIndex
= 0;
1752 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1753 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1754 elements
[idx
].UsageIndex
= 1;
1757 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1758 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1759 switch (numcoords
) {
1760 case WINED3DFVF_TEXTUREFORMAT1
:
1761 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1763 case WINED3DFVF_TEXTUREFORMAT2
:
1764 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1766 case WINED3DFVF_TEXTUREFORMAT3
:
1767 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1769 case WINED3DFVF_TEXTUREFORMAT4
:
1770 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1773 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1774 elements
[idx
].UsageIndex
= idx2
;
1778 /* Now compute offsets, and initialize the rest of the fields */
1779 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1780 elements
[idx
].Stream
= 0;
1781 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1782 elements
[idx
].Offset
= offset
;
1783 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1786 *ppVertexElements
= elements
;
1790 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1791 WINED3DVERTEXELEMENT
* elements
= NULL
;
1795 size
= ConvertFvfToDeclaration(Fvf
, &elements
);
1796 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1798 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1799 HeapFree(GetProcessHeap(), 0, elements
);
1800 if (hr
!= S_OK
) return hr
;
1805 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1806 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1808 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1809 HRESULT hr
= WINED3D_OK
;
1810 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1811 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1813 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1815 if (vertex_declaration
) {
1816 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1819 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1821 if (WINED3D_OK
!= hr
) {
1822 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1823 IWineD3DVertexShader_Release(*ppVertexShader
);
1824 return WINED3DERR_INVALIDCALL
;
1830 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1831 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1832 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1833 HRESULT hr
= WINED3D_OK
;
1835 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1836 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1837 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1838 if (WINED3D_OK
== hr
) {
1839 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1841 WARN("(%p) : Failed to create pixel shader\n", This
);
1847 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1848 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1849 IWineD3DPaletteImpl
*object
;
1851 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1853 /* Create the new object */
1854 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1856 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1857 return E_OUTOFMEMORY
;
1860 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1862 object
->Flags
= Flags
;
1863 object
->parent
= Parent
;
1864 object
->wineD3DDevice
= This
;
1865 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1867 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1870 HeapFree( GetProcessHeap(), 0, object
);
1871 return E_OUTOFMEMORY
;
1874 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1876 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1880 *Palette
= (IWineD3DPalette
*) object
;
1885 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1889 HDC dcb
= NULL
, dcs
= NULL
;
1890 WINEDDCOLORKEY colorkey
;
1892 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1895 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1896 dcb
= CreateCompatibleDC(NULL
);
1898 SelectObject(dcb
, hbm
);
1902 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1903 * couldn't be loaded
1905 memset(&bm
, 0, sizeof(bm
));
1910 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1911 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1912 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1914 ERR("Wine logo requested, but failed to create surface\n");
1919 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1920 if(FAILED(hr
)) goto out
;
1921 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1922 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1924 colorkey
.dwColorSpaceLowValue
= 0;
1925 colorkey
.dwColorSpaceHighValue
= 0;
1926 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1928 /* Fill the surface with a white color to show that wined3d is there */
1929 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1942 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
1943 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1944 IWineD3DSwapChainImpl
*swapchain
;
1948 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
1949 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1951 /* TODO: Test if OpenGL is compiled in and loaded */
1953 TRACE("(%p) : Creating stateblock\n", This
);
1954 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1955 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1957 (IWineD3DStateBlock
**)&This
->stateBlock
,
1959 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1960 WARN("Failed to create stateblock\n");
1963 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1964 This
->updateStateBlock
= This
->stateBlock
;
1965 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1967 hr
= allocate_shader_constants(This
->updateStateBlock
);
1968 if (WINED3D_OK
!= hr
) {
1972 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
1973 This
->fbo_color_attachments
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
1974 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
1976 /* Initialize the texture unit mapping to a 1:1 mapping */
1977 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
1978 if (state
< GL_LIMITS(fragment_samplers
)) {
1979 This
->texUnitMap
[state
] = state
;
1980 This
->rev_tex_unit_map
[state
] = state
;
1982 This
->texUnitMap
[state
] = -1;
1983 This
->rev_tex_unit_map
[state
] = -1;
1987 /* Setup the implicit swapchain */
1988 TRACE("Creating implicit swapchain\n");
1989 hr
=D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1990 if (FAILED(hr
) || !swapchain
) {
1991 WARN("Failed to create implicit swapchain\n");
1995 This
->NumberOfSwapChains
= 1;
1996 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1997 if(!This
->swapchains
) {
1998 ERR("Out of memory!\n");
2001 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2003 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, swapchain
->win_handle
);
2005 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2006 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2007 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2008 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2011 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2012 This
->render_targets
[0] = swapchain
->frontBuffer
;
2013 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2015 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2016 This
->activeContext
= swapchain
->context
[0];
2017 This
->lastThread
= GetCurrentThreadId();
2019 /* Depth Stencil support */
2020 This
->stencilBufferTarget
= This
->depthStencilBuffer
;
2021 if (NULL
!= This
->stencilBufferTarget
) {
2022 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2025 /* Set up some starting GL setup */
2028 /* Setup all the devices defaults */
2029 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2031 IWineD3DImpl_CheckGraphicsMemory();
2034 { /* Set a default viewport */
2038 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2039 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2042 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2045 /* Initialize the current view state */
2046 This
->view_ident
= 1;
2047 This
->contexts
[0]->last_was_rhw
= 0;
2048 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2049 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2051 switch(wined3d_settings
.offscreen_rendering_mode
) {
2054 This
->offscreenBuffer
= GL_BACK
;
2057 case ORM_BACKBUFFER
:
2059 if(GL_LIMITS(aux_buffers
) > 0) {
2060 TRACE("Using auxilliary buffer for offscreen rendering\n");
2061 This
->offscreenBuffer
= GL_AUX0
;
2063 TRACE("Using back buffer for offscreen rendering\n");
2064 This
->offscreenBuffer
= GL_BACK
;
2069 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2072 /* Clear the screen */
2073 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2074 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2077 This
->d3d_initialized
= TRUE
;
2079 if(wined3d_settings
.logo
) {
2080 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2085 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2086 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2087 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2088 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2089 This
->NumberOfSwapChains
= 0;
2091 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2093 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2094 if(This
->stateBlock
) {
2095 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2096 This
->stateBlock
= NULL
;
2101 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2102 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2105 TRACE("(%p)\n", This
);
2107 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2109 /* I don't think that the interface guarants that the device is destroyed from the same thread
2110 * it was created. Thus make sure a context is active for the glDelete* calls
2112 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2114 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2116 TRACE("Deleting high order patches\n");
2117 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2118 struct list
*e1
, *e2
;
2119 struct WineD3DRectPatch
*patch
;
2120 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2121 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2122 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2126 /* Delete the palette conversion shader if it is around */
2127 if(This
->paletteConversionShader
) {
2128 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2131 /* Delete the pbuffer context if there is any */
2132 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2134 /* Delete the mouse cursor texture */
2135 if(This
->cursorTexture
) {
2137 glDeleteTextures(1, &This
->cursorTexture
);
2139 This
->cursorTexture
= 0;
2142 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2143 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2145 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2146 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2149 /* Release the update stateblock */
2150 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2151 if(This
->updateStateBlock
!= This
->stateBlock
)
2152 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2154 This
->updateStateBlock
= NULL
;
2156 { /* because were not doing proper internal refcounts releasing the primary state block
2157 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2158 to set this->stateBlock = NULL; first */
2159 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2160 This
->stateBlock
= NULL
;
2162 /* Release the stateblock */
2163 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2164 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2168 /* Release the buffers (with sanity checks)*/
2169 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2170 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2171 if(This
->depthStencilBuffer
!= This
->stencilBufferTarget
)
2172 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This
);
2174 This
->stencilBufferTarget
= NULL
;
2176 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2177 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2178 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2180 TRACE("Setting rendertarget to NULL\n");
2181 This
->render_targets
[0] = NULL
;
2183 if (This
->depthStencilBuffer
) {
2184 if(D3DCB_DestroyDepthStencilSurface(This
->depthStencilBuffer
) > 0) {
2185 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This
);
2187 This
->depthStencilBuffer
= NULL
;
2190 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2191 TRACE("Releasing the implicit swapchain %d\n", i
);
2192 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2193 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2197 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2198 This
->swapchains
= NULL
;
2199 This
->NumberOfSwapChains
= 0;
2201 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2202 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2203 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2204 This
->render_targets
= NULL
;
2205 This
->fbo_color_attachments
= NULL
;
2206 This
->draw_buffers
= NULL
;
2209 This
->d3d_initialized
= FALSE
;
2213 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2214 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2215 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2217 /* Setup the window for fullscreen mode */
2218 if(fullscreen
&& !This
->ddraw_fullscreen
) {
2219 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
2220 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
2221 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
2224 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2225 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2226 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2229 This
->ddraw_fullscreen
= fullscreen
;
2232 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2233 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2234 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2236 * There is no way to deactivate thread safety once it is enabled.
2238 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2239 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2241 /*For now just store the flag(needed in case of ddraw) */
2242 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2247 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2249 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2251 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2254 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2256 /* Resize the screen even without a window:
2257 * The app could have unset it with SetCooperativeLevel, but not called
2258 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2259 * but we don't have any hwnd
2262 memset(&devmode
, 0, sizeof(devmode
));
2263 devmode
.dmSize
= sizeof(devmode
);
2264 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2265 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2266 if(devmode
.dmBitsPerPel
== 24) devmode
.dmBitsPerPel
= 32;
2267 devmode
.dmPelsWidth
= pMode
->Width
;
2268 devmode
.dmPelsHeight
= pMode
->Height
;
2270 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2271 if (pMode
->RefreshRate
!= 0) {
2272 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2275 /* Only change the mode if necessary */
2276 if( (This
->ddraw_width
== pMode
->Width
) &&
2277 (This
->ddraw_height
== pMode
->Height
) &&
2278 (This
->ddraw_format
== pMode
->Format
) &&
2279 (pMode
->RefreshRate
== 0) ) {
2283 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2284 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2285 if(devmode
.dmDisplayFrequency
!= 0) {
2286 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2287 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2288 devmode
.dmDisplayFrequency
= 0;
2289 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2291 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2292 return WINED3DERR_NOTAVAILABLE
;
2296 /* Store the new values */
2297 This
->ddraw_width
= pMode
->Width
;
2298 This
->ddraw_height
= pMode
->Height
;
2299 This
->ddraw_format
= pMode
->Format
;
2301 /* Only do this with a window of course */
2302 if(This
->ddraw_window
)
2303 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2305 /* And finally clip mouse to our screen */
2306 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2307 ClipCursor(&clip_rc
);
2312 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2313 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2314 *ppD3D
= This
->wineD3D
;
2315 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2316 IWineD3D_AddRef(*ppD3D
);
2320 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2321 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2323 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2324 (This
->adapter
->TextureRam
/(1024*1024)),
2325 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2326 /* return simulated texture memory left */
2327 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2335 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2336 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2338 /* Update the current state block */
2339 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2341 if(This
->updateStateBlock
->fvf
== fvf
) {
2342 TRACE("Application is setting the old fvf over, nothing to do\n");
2346 This
->updateStateBlock
->fvf
= fvf
;
2347 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2353 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2354 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2355 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2356 *pfvf
= This
->stateBlock
->fvf
;
2361 * Get / Set Stream Source
2363 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2364 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2365 IWineD3DVertexBuffer
*oldSrc
;
2367 if (StreamNumber
>= MAX_STREAMS
) {
2368 WARN("Stream out of range %d\n", StreamNumber
);
2369 return WINED3DERR_INVALIDCALL
;
2372 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2373 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2375 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2377 if(oldSrc
== pStreamData
&&
2378 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2379 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2380 TRACE("Application is setting the old values over, nothing to do\n");
2384 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2386 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2387 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2390 /* Handle recording of state blocks */
2391 if (This
->isRecordingState
) {
2392 TRACE("Recording... not performing anything\n");
2393 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2394 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2398 /* Need to do a getParent and pass the reffs up */
2399 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2400 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2401 so for now, just count internally */
2402 if (pStreamData
!= NULL
) {
2403 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2404 InterlockedIncrement(&vbImpl
->bindCount
);
2405 IWineD3DVertexBuffer_AddRef(pStreamData
);
2407 if (oldSrc
!= NULL
) {
2408 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2409 IWineD3DVertexBuffer_Release(oldSrc
);
2412 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2417 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2418 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2420 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2421 This
->stateBlock
->streamSource
[StreamNumber
],
2422 This
->stateBlock
->streamOffset
[StreamNumber
],
2423 This
->stateBlock
->streamStride
[StreamNumber
]);
2425 if (StreamNumber
>= MAX_STREAMS
) {
2426 WARN("Stream out of range %d\n", StreamNumber
);
2427 return WINED3DERR_INVALIDCALL
;
2429 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2430 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2432 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2435 if (*pStream
!= NULL
) {
2436 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2441 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2442 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2443 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2444 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2446 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2447 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2449 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2450 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2452 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2453 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2454 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2460 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2461 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2463 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2464 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2466 TRACE("(%p) : returning %d\n", This
, *Divider
);
2472 * Get / Set & Multiply Transform
2474 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2475 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2477 /* Most of this routine, comments included copied from ddraw tree initially: */
2478 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2480 /* Handle recording of state blocks */
2481 if (This
->isRecordingState
) {
2482 TRACE("Recording... not performing anything\n");
2483 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2484 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2489 * If the new matrix is the same as the current one,
2490 * we cut off any further processing. this seems to be a reasonable
2491 * optimization because as was noticed, some apps (warcraft3 for example)
2492 * tend towards setting the same matrix repeatedly for some reason.
2494 * From here on we assume that the new matrix is different, wherever it matters.
2496 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2497 TRACE("The app is setting the same matrix over again\n");
2500 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2504 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2505 where ViewMat = Camera space, WorldMat = world space.
2507 In OpenGL, camera and world space is combined into GL_MODELVIEW
2508 matrix. The Projection matrix stay projection matrix.
2511 /* Capture the times we can just ignore the change for now */
2512 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2513 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2514 /* Handled by the state manager */
2517 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2521 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2523 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2524 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2528 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2529 WINED3DMATRIX
*mat
= NULL
;
2532 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2533 * below means it will be recorded in a state block change, but it
2534 * works regardless where it is recorded.
2535 * If this is found to be wrong, change to StateBlock.
2537 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2538 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2540 if (State
< HIGHEST_TRANSFORMSTATE
)
2542 mat
= &This
->updateStateBlock
->transforms
[State
];
2544 FIXME("Unhandled transform state!!\n");
2547 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2549 /* Apply change via set transform - will reapply to eg. lights this way */
2550 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2556 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2557 you can reference any indexes you want as long as that number max are enabled at any
2558 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2559 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2560 but when recording, just build a chain pretty much of commands to be replayed. */
2562 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2564 PLIGHTINFOEL
*object
= NULL
;
2565 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2568 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2569 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2571 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2575 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2576 return WINED3DERR_INVALIDCALL
;
2579 switch(pLight
->Type
) {
2580 case WINED3DLIGHT_POINT
:
2581 case WINED3DLIGHT_SPOT
:
2582 case WINED3DLIGHT_PARALLELPOINT
:
2583 case WINED3DLIGHT_GLSPOT
:
2584 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2587 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2588 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2589 return WINED3DERR_INVALIDCALL
;
2593 case WINED3DLIGHT_DIRECTIONAL
:
2594 /* Ignores attenuation */
2598 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2599 return WINED3DERR_INVALIDCALL
;
2602 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2603 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2604 if(object
->OriginalIndex
== Index
) break;
2609 TRACE("Adding new light\n");
2610 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2612 ERR("Out of memory error when allocating a light\n");
2613 return E_OUTOFMEMORY
;
2615 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2616 object
->glIndex
= -1;
2617 object
->OriginalIndex
= Index
;
2618 object
->changed
= TRUE
;
2621 /* Initialize the object */
2622 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
,
2623 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2624 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2625 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2626 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2627 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2628 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2630 /* Save away the information */
2631 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2633 switch (pLight
->Type
) {
2634 case WINED3DLIGHT_POINT
:
2636 object
->lightPosn
[0] = pLight
->Position
.x
;
2637 object
->lightPosn
[1] = pLight
->Position
.y
;
2638 object
->lightPosn
[2] = pLight
->Position
.z
;
2639 object
->lightPosn
[3] = 1.0f
;
2640 object
->cutoff
= 180.0f
;
2644 case WINED3DLIGHT_DIRECTIONAL
:
2646 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2647 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2648 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2649 object
->lightPosn
[3] = 0.0;
2650 object
->exponent
= 0.0f
;
2651 object
->cutoff
= 180.0f
;
2654 case WINED3DLIGHT_SPOT
:
2656 object
->lightPosn
[0] = pLight
->Position
.x
;
2657 object
->lightPosn
[1] = pLight
->Position
.y
;
2658 object
->lightPosn
[2] = pLight
->Position
.z
;
2659 object
->lightPosn
[3] = 1.0;
2662 object
->lightDirn
[0] = pLight
->Direction
.x
;
2663 object
->lightDirn
[1] = pLight
->Direction
.y
;
2664 object
->lightDirn
[2] = pLight
->Direction
.z
;
2665 object
->lightDirn
[3] = 1.0;
2668 * opengl-ish and d3d-ish spot lights use too different models for the
2669 * light "intensity" as a function of the angle towards the main light direction,
2670 * so we only can approximate very roughly.
2671 * however spot lights are rather rarely used in games (if ever used at all).
2672 * furthermore if still used, probably nobody pays attention to such details.
2674 if (pLight
->Falloff
== 0) {
2675 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2676 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2677 * will always be 1.0 for both of them, and we don't have to care for the
2678 * rest of the rather complex calculation
2680 object
->exponent
= 0;
2682 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2683 if (rho
< 0.0001) rho
= 0.0001f
;
2684 object
->exponent
= -0.3/log(cos(rho
/2));
2686 if (object
->exponent
> 128.0) {
2687 object
->exponent
= 128.0;
2689 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2695 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2698 /* Update the live definitions if the light is currently assigned a glIndex */
2699 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2700 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2705 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2706 PLIGHTINFOEL
*lightInfo
= NULL
;
2707 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2708 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2710 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2712 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2713 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2714 if(lightInfo
->OriginalIndex
== Index
) break;
2718 if (lightInfo
== NULL
) {
2719 TRACE("Light information requested but light not defined\n");
2720 return WINED3DERR_INVALIDCALL
;
2723 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2728 * Get / Set Light Enable
2729 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2731 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2732 PLIGHTINFOEL
*lightInfo
= NULL
;
2733 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2734 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2736 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2738 /* Tests show true = 128...not clear why */
2739 Enable
= Enable
? 128: 0;
2741 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2742 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2743 if(lightInfo
->OriginalIndex
== Index
) break;
2746 TRACE("Found light: %p\n", lightInfo
);
2748 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2749 if (lightInfo
== NULL
) {
2751 TRACE("Light enabled requested but light not defined, so defining one!\n");
2752 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2754 /* Search for it again! Should be fairly quick as near head of list */
2755 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2756 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2757 if(lightInfo
->OriginalIndex
== Index
) break;
2760 if (lightInfo
== NULL
) {
2761 FIXME("Adding default lights has failed dismally\n");
2762 return WINED3DERR_INVALIDCALL
;
2766 lightInfo
->enabledChanged
= TRUE
;
2768 if(lightInfo
->glIndex
!= -1) {
2769 if(!This
->isRecordingState
) {
2770 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2773 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2774 lightInfo
->glIndex
= -1;
2776 TRACE("Light already disabled, nothing to do\n");
2779 if (lightInfo
->glIndex
!= -1) {
2781 TRACE("Nothing to do as light was enabled\n");
2784 /* Find a free gl light */
2785 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2786 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2787 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2788 lightInfo
->glIndex
= i
;
2792 if(lightInfo
->glIndex
== -1) {
2793 ERR("Too many concurrently active lights\n");
2794 return WINED3DERR_INVALIDCALL
;
2797 /* i == lightInfo->glIndex */
2798 if(!This
->isRecordingState
) {
2799 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2807 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2809 PLIGHTINFOEL
*lightInfo
= NULL
;
2810 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2812 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2813 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2815 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2816 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2817 if(lightInfo
->OriginalIndex
== Index
) break;
2821 if (lightInfo
== NULL
) {
2822 TRACE("Light enabled state requested but light not defined\n");
2823 return WINED3DERR_INVALIDCALL
;
2825 /* true is 128 according to SetLightEnable */
2826 *pEnable
= lightInfo
->glIndex
!= -1 ? 128 : 0;
2831 * Get / Set Clip Planes
2833 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2834 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2835 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2837 /* Validate Index */
2838 if (Index
>= GL_LIMITS(clipplanes
)) {
2839 TRACE("Application has requested clipplane this device doesn't support\n");
2840 return WINED3DERR_INVALIDCALL
;
2843 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2845 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2846 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2847 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2848 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2849 TRACE("Application is setting old values over, nothing to do\n");
2853 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2854 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2855 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2856 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2858 /* Handle recording of state blocks */
2859 if (This
->isRecordingState
) {
2860 TRACE("Recording... not performing anything\n");
2864 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2869 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2870 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2871 TRACE("(%p) : for idx %d\n", This
, Index
);
2873 /* Validate Index */
2874 if (Index
>= GL_LIMITS(clipplanes
)) {
2875 TRACE("Application has requested clipplane this device doesn't support\n");
2876 return WINED3DERR_INVALIDCALL
;
2879 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2880 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2881 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2882 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2887 * Get / Set Clip Plane Status
2888 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2890 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2891 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2892 FIXME("(%p) : stub\n", This
);
2893 if (NULL
== pClipStatus
) {
2894 return WINED3DERR_INVALIDCALL
;
2896 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2897 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2901 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2902 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2903 FIXME("(%p) : stub\n", This
);
2904 if (NULL
== pClipStatus
) {
2905 return WINED3DERR_INVALIDCALL
;
2907 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2908 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2913 * Get / Set Material
2915 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2916 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2918 This
->updateStateBlock
->changed
.material
= TRUE
;
2919 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2921 /* Handle recording of state blocks */
2922 if (This
->isRecordingState
) {
2923 TRACE("Recording... not performing anything\n");
2927 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2931 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2932 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2933 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
2934 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2935 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2936 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2937 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2938 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2939 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2940 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2941 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2942 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2950 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
2951 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2952 IWineD3DIndexBuffer
*oldIdxs
;
2954 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2955 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2957 This
->updateStateBlock
->changed
.indices
= TRUE
;
2958 This
->updateStateBlock
->pIndexData
= pIndexData
;
2960 /* Handle recording of state blocks */
2961 if (This
->isRecordingState
) {
2962 TRACE("Recording... not performing anything\n");
2963 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
2964 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
2968 if(oldIdxs
!= pIndexData
) {
2969 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2970 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
2971 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
2976 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
2977 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2979 *ppIndexData
= This
->stateBlock
->pIndexData
;
2981 /* up ref count on ppindexdata */
2983 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
2984 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2986 TRACE("(%p) No index data set\n", This
);
2988 TRACE("Returning %p\n", *ppIndexData
);
2993 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2994 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2995 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2996 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2998 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2999 TRACE("Application is setting the old value over, nothing to do\n");
3003 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3005 if (This
->isRecordingState
) {
3006 TRACE("Recording... not performing anything\n");
3009 /* The base vertex index affects the stream sources */
3010 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3014 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3015 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3016 TRACE("(%p) : base_index %p\n", This
, base_index
);
3018 *base_index
= This
->stateBlock
->baseVertexIndex
;
3020 TRACE("Returning %u\n", *base_index
);
3026 * Get / Set Viewports
3028 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3029 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3031 TRACE("(%p)\n", This
);
3032 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3033 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
3035 /* Handle recording of state blocks */
3036 if (This
->isRecordingState
) {
3037 TRACE("Recording... not performing anything\n");
3041 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3042 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3044 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3049 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3050 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3051 TRACE("(%p)\n", This
);
3052 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
3057 * Get / Set Render States
3058 * TODO: Verify against dx9 definitions
3060 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3062 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3063 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3065 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3067 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3068 This
->updateStateBlock
->renderState
[State
] = Value
;
3070 /* Handle recording of state blocks */
3071 if (This
->isRecordingState
) {
3072 TRACE("Recording... not performing anything\n");
3076 /* Compared here and not before the assignment to allow proper stateblock recording */
3077 if(Value
== oldValue
) {
3078 TRACE("Application is setting the old value over, nothing to do\n");
3080 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3086 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3087 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3088 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3089 *pValue
= This
->stateBlock
->renderState
[State
];
3094 * Get / Set Sampler States
3095 * TODO: Verify against dx9 definitions
3098 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3099 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3102 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3103 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3105 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3106 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3110 * SetSampler is designed to allow for more than the standard up to 8 textures
3111 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3112 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3114 * http://developer.nvidia.com/object/General_FAQ.html#t6
3116 * There are two new settings for GForce
3118 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3119 * and the texture one:
3120 * GL_MAX_TEXTURE_COORDS_ARB.
3121 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3124 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3125 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3126 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3128 /* Handle recording of state blocks */
3129 if (This
->isRecordingState
) {
3130 TRACE("Recording... not performing anything\n");
3134 if(oldValue
== Value
) {
3135 TRACE("Application is setting the old value over, nothing to do\n");
3139 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3144 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3145 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3147 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3148 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3150 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3151 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3154 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3155 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3160 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3161 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3163 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3164 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3165 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3168 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3170 if(This
->isRecordingState
) {
3171 TRACE("Recording... not performing anything\n");
3175 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3180 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3181 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3183 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
3184 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3188 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3189 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3190 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3192 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3194 This
->updateStateBlock
->vertexDecl
= pDecl
;
3195 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3197 if (This
->isRecordingState
) {
3198 TRACE("Recording... not performing anything\n");
3200 } else if(pDecl
== oldDecl
) {
3201 /* Checked after the assignment to allow proper stateblock recording */
3202 TRACE("Application is setting the old declaration over, nothing to do\n");
3206 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3210 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3211 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3213 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3215 *ppDecl
= This
->stateBlock
->vertexDecl
;
3216 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3220 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3221 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3222 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3224 This
->updateStateBlock
->vertexShader
= pShader
;
3225 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3227 if (This
->isRecordingState
) {
3228 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3229 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3230 TRACE("Recording... not performing anything\n");
3232 } else if(oldShader
== pShader
) {
3233 /* Checked here to allow proper stateblock recording */
3234 TRACE("App is setting the old shader over, nothing to do\n");
3238 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3239 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3240 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3242 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3247 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3248 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3250 if (NULL
== ppShader
) {
3251 return WINED3DERR_INVALIDCALL
;
3253 *ppShader
= This
->stateBlock
->vertexShader
;
3254 if( NULL
!= *ppShader
)
3255 IWineD3DVertexShader_AddRef(*ppShader
);
3257 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3261 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3262 IWineD3DDevice
*iface
,
3264 CONST BOOL
*srcData
,
3267 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3268 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3270 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3271 iface
, srcData
, start
, count
);
3273 if (srcData
== NULL
|| cnt
< 0)
3274 return WINED3DERR_INVALIDCALL
;
3276 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3277 for (i
= 0; i
< cnt
; i
++)
3278 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3280 for (i
= start
; i
< cnt
+ start
; ++i
) {
3281 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3284 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3289 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3290 IWineD3DDevice
*iface
,
3295 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3296 int cnt
= min(count
, MAX_CONST_B
- start
);
3298 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3299 iface
, dstData
, start
, count
);
3301 if (dstData
== NULL
|| cnt
< 0)
3302 return WINED3DERR_INVALIDCALL
;
3304 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3308 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3309 IWineD3DDevice
*iface
,
3314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3315 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3317 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3318 iface
, srcData
, start
, count
);
3320 if (srcData
== NULL
|| cnt
< 0)
3321 return WINED3DERR_INVALIDCALL
;
3323 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3324 for (i
= 0; i
< cnt
; i
++)
3325 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3326 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3328 for (i
= start
; i
< cnt
+ start
; ++i
) {
3329 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3332 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3337 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3338 IWineD3DDevice
*iface
,
3343 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3344 int cnt
= min(count
, MAX_CONST_I
- start
);
3346 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3347 iface
, dstData
, start
, count
);
3349 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3350 return WINED3DERR_INVALIDCALL
;
3352 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3356 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3357 IWineD3DDevice
*iface
,
3359 CONST
float *srcData
,
3362 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3365 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3366 iface
, srcData
, start
, count
);
3368 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3369 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3370 return WINED3DERR_INVALIDCALL
;
3372 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3374 for (i
= 0; i
< count
; i
++)
3375 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3376 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3379 for (i
= start
; i
< count
+ start
; ++i
) {
3380 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3381 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3382 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3383 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3384 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3386 ptr
->idx
[ptr
->count
++] = i
;
3387 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3391 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3396 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3397 IWineD3DDevice
*iface
,
3402 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3403 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3405 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3406 iface
, dstData
, start
, count
);
3408 if (dstData
== NULL
|| cnt
< 0)
3409 return WINED3DERR_INVALIDCALL
;
3411 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3415 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3417 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3418 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3422 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3423 int i
= This
->rev_tex_unit_map
[unit
];
3424 int j
= This
->texUnitMap
[stage
];
3426 This
->texUnitMap
[stage
] = unit
;
3427 if (i
!= -1 && i
!= stage
) {
3428 This
->texUnitMap
[i
] = -1;
3431 This
->rev_tex_unit_map
[unit
] = stage
;
3432 if (j
!= -1 && j
!= unit
) {
3433 This
->rev_tex_unit_map
[j
] = -1;
3437 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3440 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3441 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3442 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3443 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3444 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3445 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3446 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3447 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3448 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3450 if (color_op
== WINED3DTOP_DISABLE
) {
3451 /* Not used, and disable higher stages */
3452 while (i
< MAX_TEXTURES
) {
3453 This
->fixed_function_usage_map
[i
] = FALSE
;
3459 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3460 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3461 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3462 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3463 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3464 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3465 This
->fixed_function_usage_map
[i
] = TRUE
;
3467 This
->fixed_function_usage_map
[i
] = FALSE
;
3470 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3471 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3476 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3479 device_update_fixed_function_usage_map(This
);
3481 if (!GL_SUPPORT(NV_REGISTER_COMBINERS
) || This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3482 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3483 if (!This
->fixed_function_usage_map
[i
]) continue;
3485 if (This
->texUnitMap
[i
] != i
) {
3486 device_map_stage(This
, i
, i
);
3487 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3488 markTextureStagesDirty(This
, i
);
3494 /* Now work out the mapping */
3496 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3497 if (!This
->fixed_function_usage_map
[i
]) continue;
3499 if (This
->texUnitMap
[i
] != tex
) {
3500 device_map_stage(This
, i
, tex
);
3501 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3502 markTextureStagesDirty(This
, i
);
3509 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3510 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3513 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3514 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3515 device_map_stage(This
, i
, i
);
3516 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3517 if (i
< MAX_TEXTURES
) {
3518 markTextureStagesDirty(This
, i
);
3524 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3525 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3527 if (current_mapping
== -1) {
3528 /* Not currently used */
3532 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3533 /* Used by a fragment sampler */
3535 if (!pshader_sampler_tokens
) {
3536 /* No pixel shader, check fixed function */
3537 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3540 /* Pixel shader, check the shader's sampler map */
3541 return !pshader_sampler_tokens
[current_mapping
];
3544 /* Used by a vertex sampler */
3545 return !vshader_sampler_tokens
[current_mapping
];
3548 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3549 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3550 DWORD
*pshader_sampler_tokens
= NULL
;
3551 int start
= GL_LIMITS(combined_samplers
) - 1;
3555 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3557 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3558 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3559 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3562 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3563 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3564 if (vshader_sampler_tokens
[i
]) {
3565 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3566 /* Already mapped somewhere */
3570 while (start
>= 0) {
3571 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3572 device_map_stage(This
, vsampler_idx
, start
);
3573 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3585 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3586 BOOL vs
= use_vs(This
);
3587 BOOL ps
= use_ps(This
);
3590 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3591 * that would be really messy and require shader recompilation
3592 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3593 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3596 device_map_psamplers(This
);
3598 device_map_fixed_function_samplers(This
);
3602 device_map_vsamplers(This
, ps
);
3606 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3607 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3608 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3609 This
->updateStateBlock
->pixelShader
= pShader
;
3610 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3612 /* Handle recording of state blocks */
3613 if (This
->isRecordingState
) {
3614 TRACE("Recording... not performing anything\n");
3617 if (This
->isRecordingState
) {
3618 TRACE("Recording... not performing anything\n");
3619 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3620 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3624 if(pShader
== oldShader
) {
3625 TRACE("App is setting the old pixel shader over, nothing to do\n");
3629 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3630 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3632 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3633 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3638 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3639 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3641 if (NULL
== ppShader
) {
3642 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3643 return WINED3DERR_INVALIDCALL
;
3646 *ppShader
= This
->stateBlock
->pixelShader
;
3647 if (NULL
!= *ppShader
) {
3648 IWineD3DPixelShader_AddRef(*ppShader
);
3650 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3654 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3655 IWineD3DDevice
*iface
,
3657 CONST BOOL
*srcData
,
3660 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3661 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3663 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3664 iface
, srcData
, start
, count
);
3666 if (srcData
== NULL
|| cnt
< 0)
3667 return WINED3DERR_INVALIDCALL
;
3669 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3670 for (i
= 0; i
< cnt
; i
++)
3671 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3673 for (i
= start
; i
< cnt
+ start
; ++i
) {
3674 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3677 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3682 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3683 IWineD3DDevice
*iface
,
3688 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3689 int cnt
= min(count
, MAX_CONST_B
- start
);
3691 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3692 iface
, dstData
, start
, count
);
3694 if (dstData
== NULL
|| cnt
< 0)
3695 return WINED3DERR_INVALIDCALL
;
3697 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3701 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3702 IWineD3DDevice
*iface
,
3707 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3708 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3710 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3711 iface
, srcData
, start
, count
);
3713 if (srcData
== NULL
|| cnt
< 0)
3714 return WINED3DERR_INVALIDCALL
;
3716 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3717 for (i
= 0; i
< cnt
; i
++)
3718 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3719 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3721 for (i
= start
; i
< cnt
+ start
; ++i
) {
3722 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3725 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3730 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3731 IWineD3DDevice
*iface
,
3736 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3737 int cnt
= min(count
, MAX_CONST_I
- start
);
3739 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3740 iface
, dstData
, start
, count
);
3742 if (dstData
== NULL
|| cnt
< 0)
3743 return WINED3DERR_INVALIDCALL
;
3745 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3749 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3750 IWineD3DDevice
*iface
,
3752 CONST
float *srcData
,
3755 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3758 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3759 iface
, srcData
, start
, count
);
3761 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3762 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3763 return WINED3DERR_INVALIDCALL
;
3765 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3767 for (i
= 0; i
< count
; i
++)
3768 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3769 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3772 for (i
= start
; i
< count
+ start
; ++i
) {
3773 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
3774 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
3775 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3776 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3777 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3779 ptr
->idx
[ptr
->count
++] = i
;
3780 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3784 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3789 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3790 IWineD3DDevice
*iface
,
3795 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3796 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3799 iface
, dstData
, start
, count
);
3801 if (dstData
== NULL
|| cnt
< 0)
3802 return WINED3DERR_INVALIDCALL
;
3804 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3808 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3810 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3811 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3813 DWORD DestFVF
= dest
->fvf
;
3815 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3819 if (lpStrideData
->u
.s
.normal
.lpData
) {
3820 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3823 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
3824 ERR("Source has no position mask\n");
3825 return WINED3DERR_INVALIDCALL
;
3828 /* We might access VBOs from this code, so hold the lock */
3831 if (dest
->resource
.allocatedMemory
== NULL
) {
3832 /* This may happen if we do direct locking into a vbo. Unlikely,
3833 * but theoretically possible(ddraw processvertices test)
3835 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3836 if(!dest
->resource
.allocatedMemory
) {
3838 ERR("Out of memory\n");
3839 return E_OUTOFMEMORY
;
3843 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3844 checkGLcall("glBindBufferARB");
3845 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3847 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3849 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3850 checkGLcall("glUnmapBufferARB");
3854 /* Get a pointer into the destination vbo(create one if none exists) and
3855 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3857 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3862 unsigned char extrabytes
= 0;
3863 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3864 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3865 * this may write 4 extra bytes beyond the area that should be written
3867 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3868 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3869 if(!dest_conv_addr
) {
3870 ERR("Out of memory\n");
3871 /* Continue without storing converted vertices */
3873 dest_conv
= dest_conv_addr
;
3877 * a) WINED3DRS_CLIPPING is enabled
3878 * b) WINED3DVOP_CLIP is passed
3880 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3881 static BOOL warned
= FALSE
;
3883 * The clipping code is not quite correct. Some things need
3884 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3885 * so disable clipping for now.
3886 * (The graphics in Half-Life are broken, and my processvertices
3887 * test crashes with IDirect3DDevice3)
3893 FIXME("Clipping is broken and disabled for now\n");
3895 } else doClip
= FALSE
;
3896 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3898 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3901 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3902 WINED3DTS_PROJECTION
,
3904 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3905 WINED3DTS_WORLDMATRIX(0),
3908 TRACE("View mat:\n");
3909 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
);
3910 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
);
3911 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
);
3912 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
);
3914 TRACE("Proj mat:\n");
3915 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
);
3916 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
);
3917 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
);
3918 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
);
3920 TRACE("World mat:\n");
3921 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
);
3922 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
);
3923 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
);
3924 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
);
3926 /* Get the viewport */
3927 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3928 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3929 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3931 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3932 multiply_matrix(&mat
,&proj_mat
,&mat
);
3934 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3936 for (i
= 0; i
< dwCount
; i
+= 1) {
3937 unsigned int tex_index
;
3939 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3940 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3941 /* The position first */
3943 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
3945 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3947 /* Multiplication with world, view and projection matrix */
3948 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
);
3949 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
);
3950 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
);
3951 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
);
3953 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3955 /* WARNING: The following things are taken from d3d7 and were not yet checked
3956 * against d3d8 or d3d9!
3959 /* Clipping conditions: From
3960 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3962 * A vertex is clipped if it does not match the following requirements
3966 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3968 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3969 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3974 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3975 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3978 /* "Normal" viewport transformation (not clipped)
3979 * 1) The values are divided by rhw
3980 * 2) The y axis is negative, so multiply it with -1
3981 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3982 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3983 * 4) Multiply x with Width/2 and add Width/2
3984 * 5) The same for the height
3985 * 6) Add the viewpoint X and Y to the 2D coordinates and
3986 * The minimum Z value to z
3987 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3989 * Well, basically it's simply a linear transformation into viewport
4001 z
*= vp
.MaxZ
- vp
.MinZ
;
4003 x
+= vp
.Width
/ 2 + vp
.X
;
4004 y
+= vp
.Height
/ 2 + vp
.Y
;
4009 /* That vertex got clipped
4010 * Contrary to OpenGL it is not dropped completely, it just
4011 * undergoes a different calculation.
4013 TRACE("Vertex got clipped\n");
4020 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4021 * outside of the main vertex buffer memory. That needs some more
4026 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4029 ( (float *) dest_ptr
)[0] = x
;
4030 ( (float *) dest_ptr
)[1] = y
;
4031 ( (float *) dest_ptr
)[2] = z
;
4032 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4034 dest_ptr
+= 3 * sizeof(float);
4036 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4037 dest_ptr
+= sizeof(float);
4042 ( (float *) dest_conv
)[0] = x
* w
;
4043 ( (float *) dest_conv
)[1] = y
* w
;
4044 ( (float *) dest_conv
)[2] = z
* w
;
4045 ( (float *) dest_conv
)[3] = w
;
4047 dest_conv
+= 3 * sizeof(float);
4049 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4050 dest_conv
+= sizeof(float);
4054 if (DestFVF
& WINED3DFVF_PSIZE
) {
4055 dest_ptr
+= sizeof(DWORD
);
4056 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4058 if (DestFVF
& WINED3DFVF_NORMAL
) {
4060 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4061 /* AFAIK this should go into the lighting information */
4062 FIXME("Didn't expect the destination to have a normal\n");
4063 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4065 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4069 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4071 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4073 static BOOL warned
= FALSE
;
4076 ERR("No diffuse color in source, but destination has one\n");
4080 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4081 dest_ptr
+= sizeof(DWORD
);
4084 *( (DWORD
*) dest_conv
) = 0xffffffff;
4085 dest_conv
+= sizeof(DWORD
);
4089 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4091 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4092 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4093 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4094 dest_conv
+= sizeof(DWORD
);
4099 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4100 /* What's the color value in the feedback buffer? */
4102 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4104 static BOOL warned
= FALSE
;
4107 ERR("No specular color in source, but destination has one\n");
4111 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4112 dest_ptr
+= sizeof(DWORD
);
4115 *( (DWORD
*) dest_conv
) = 0xFF000000;
4116 dest_conv
+= sizeof(DWORD
);
4120 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4122 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4123 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4124 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4125 dest_conv
+= sizeof(DWORD
);
4130 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4132 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4133 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4135 ERR("No source texture, but destination requests one\n");
4136 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4137 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4140 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4142 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4149 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4150 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4151 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4152 dwCount
* get_flexible_vertex_size(DestFVF
),
4154 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4155 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4162 #undef copy_and_next
4164 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4165 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4166 WineDirect3DVertexStridedData strided
;
4167 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4168 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4171 ERR("Output vertex declaration not implemented yet\n");
4174 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4175 * and this call is quite performance critical, so don't call needlessly
4177 if(This
->createParms
.BehaviorFlags
& WINED3DCREATE_MULTITHREADED
) {
4178 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4181 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4182 * control the streamIsUP flag, thus restore it afterwards.
4184 This
->stateBlock
->streamIsUP
= FALSE
;
4185 memset(&strided
, 0, sizeof(strided
));
4186 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4187 This
->stateBlock
->streamIsUP
= streamWasUP
;
4189 if(vbo
|| SrcStartIndex
) {
4191 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4192 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4194 * Also get the start index in, but only loop over all elements if there's something to add at all.
4196 #define FIXSRC(type) \
4197 if(strided.u.s.type.VBO) { \
4198 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4199 strided.u.s.type.VBO = 0; \
4200 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4202 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4206 if(strided.u.s.type.lpData) { \
4207 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4210 FIXSRC(blendWeights
);
4211 FIXSRC(blendMatrixIndices
);
4216 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4217 FIXSRC(texCoords
[i
]);
4230 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4234 * Get / Set Texture Stage States
4235 * TODO: Verify against dx9 definitions
4237 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4238 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4239 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4241 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4243 if (Stage
>= MAX_TEXTURES
) {
4244 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4248 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4249 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4251 if (This
->isRecordingState
) {
4252 TRACE("Recording... not performing anything\n");
4256 /* Checked after the assignments to allow proper stateblock recording */
4257 if(oldValue
== Value
) {
4258 TRACE("App is setting the old value over, nothing to do\n");
4262 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4263 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4264 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4265 * Changes in other states are important on disabled stages too
4270 if(Type
== WINED3DTSS_COLOROP
) {
4273 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4274 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4275 * they have to be disabled
4277 * The current stage is dirtified below.
4279 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4280 TRACE("Additionally dirtifying stage %d\n", i
);
4281 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4283 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4284 TRACE("New lowest disabled: %d\n", Stage
);
4285 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4286 /* Previously disabled stage enabled. Stages above it may need enabling
4287 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4288 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4290 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4293 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4294 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4297 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4298 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4300 This
->stateBlock
->lowest_disabled_stage
= i
;
4301 TRACE("New lowest disabled: %d\n", i
);
4303 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4304 /* TODO: Built a stage -> texture unit mapping for register combiners */
4308 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4313 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4315 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4316 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4323 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4324 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4325 IWineD3DBaseTexture
*oldTexture
;
4327 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4329 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4330 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4333 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4335 if(pTexture
!= NULL
) {
4336 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4338 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4339 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4340 return WINED3DERR_INVALIDCALL
;
4342 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4345 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4346 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4348 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4349 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4350 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4352 /* Handle recording of state blocks */
4353 if (This
->isRecordingState
) {
4354 TRACE("Recording... not performing anything\n");
4358 if(oldTexture
== pTexture
) {
4359 TRACE("App is setting the same texture again, nothing to do\n");
4363 /** NOTE: MSDN says that setTexture increases the reference count,
4364 * and the the application must set the texture back to null (or have a leaky application),
4365 * This means we should pass the refcount up to the parent
4366 *******************************/
4367 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4368 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4369 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4371 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4372 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4373 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4374 * so the COLOROP and ALPHAOP have to be dirtified.
4376 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4377 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4379 if(bindCount
== 1) {
4380 new->baseTexture
.sampler
= Stage
;
4382 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4386 if (NULL
!= oldTexture
) {
4387 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4388 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4390 IWineD3DBaseTexture_Release(oldTexture
);
4391 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4392 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4393 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4396 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4398 /* Have to do a search for the other sampler(s) where the texture is bound to
4399 * Shouldn't happen as long as apps bind a texture only to one stage
4401 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4402 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4403 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4404 old
->baseTexture
.sampler
= i
;
4411 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4416 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4417 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4419 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4421 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4422 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4425 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4427 IWineD3DBaseTexture_AddRef(*ppTexture
);
4429 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4437 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4438 IWineD3DSurface
**ppBackBuffer
) {
4439 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4440 IWineD3DSwapChain
*swapChain
;
4443 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4445 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4446 if (hr
== WINED3D_OK
) {
4447 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4448 IWineD3DSwapChain_Release(swapChain
);
4450 *ppBackBuffer
= NULL
;
4455 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4456 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4457 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4458 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4461 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4462 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4463 IWineD3DSwapChain
*swapChain
;
4466 if(iSwapChain
> 0) {
4467 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4468 if (hr
== WINED3D_OK
) {
4469 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4470 IWineD3DSwapChain_Release(swapChain
);
4472 FIXME("(%p) Error getting display mode\n", This
);
4475 /* Don't read the real display mode,
4476 but return the stored mode instead. X11 can't change the color
4477 depth, and some apps are pretty angry if they SetDisplayMode from
4478 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4480 Also don't relay to the swapchain because with ddraw it's possible
4481 that there isn't a swapchain at all */
4482 pMode
->Width
= This
->ddraw_width
;
4483 pMode
->Height
= This
->ddraw_height
;
4484 pMode
->Format
= This
->ddraw_format
;
4485 pMode
->RefreshRate
= 0;
4492 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4493 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4494 TRACE("(%p)->(%p)\n", This
, hWnd
);
4496 if(This
->ddraw_fullscreen
) {
4497 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4498 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4500 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4501 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4505 This
->ddraw_window
= hWnd
;
4509 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4510 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4511 TRACE("(%p)->(%p)\n", This
, hWnd
);
4513 *hWnd
= This
->ddraw_window
;
4518 * Stateblock related functions
4521 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4523 IWineD3DStateBlockImpl
*object
;
4524 HRESULT temp_result
;
4527 TRACE("(%p)\n", This
);
4529 if (This
->isRecordingState
) {
4530 return WINED3DERR_INVALIDCALL
;
4533 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4534 if (NULL
== object
) {
4535 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4536 return E_OUTOFMEMORY
;
4538 TRACE("(%p) created object %p\n", This
, object
);
4539 object
->wineD3DDevice
= This
;
4540 /** FIXME: object->parent = parent; **/
4541 object
->parent
= NULL
;
4542 object
->blockType
= WINED3DSBT_RECORDED
;
4544 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4546 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4547 list_init(&object
->lightMap
[i
]);
4550 temp_result
= allocate_shader_constants(object
);
4551 if (WINED3D_OK
!= temp_result
)
4554 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4555 This
->updateStateBlock
= object
;
4556 This
->isRecordingState
= TRUE
;
4558 TRACE("(%p) recording stateblock %p\n",This
, object
);
4562 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4563 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4565 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4567 if (!This
->isRecordingState
) {
4568 FIXME("(%p) not recording! returning error\n", This
);
4569 *ppStateBlock
= NULL
;
4570 return WINED3DERR_INVALIDCALL
;
4573 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4574 if(object
->changed
.renderState
[i
]) {
4575 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4576 object
->num_contained_render_states
++;
4579 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4580 if(object
->changed
.transform
[i
]) {
4581 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4582 object
->num_contained_transform_states
++;
4585 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4586 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4587 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4588 object
->num_contained_vs_consts_f
++;
4591 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4592 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4593 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4594 object
->num_contained_vs_consts_i
++;
4597 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4598 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4599 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4600 object
->num_contained_vs_consts_b
++;
4603 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4604 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4605 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4606 object
->num_contained_ps_consts_i
++;
4609 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4610 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4611 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4612 object
->num_contained_ps_consts_b
++;
4615 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4616 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4617 if(object
->changed
.textureState
[i
][j
]) {
4618 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4619 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4620 object
->num_contained_tss_states
++;
4624 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4625 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4626 if(object
->changed
.samplerState
[i
][j
]) {
4627 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4628 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4629 object
->num_contained_sampler_states
++;
4634 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4635 This
->isRecordingState
= FALSE
;
4636 This
->updateStateBlock
= This
->stateBlock
;
4637 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4638 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4639 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4644 * Scene related functions
4646 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4647 /* At the moment we have no need for any functionality at the beginning
4649 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4650 TRACE("(%p)\n", This
);
4653 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4654 return WINED3DERR_INVALIDCALL
;
4656 This
->inScene
= TRUE
;
4660 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4661 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4662 TRACE("(%p)\n", This
);
4664 if(!This
->inScene
) {
4665 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4666 return WINED3DERR_INVALIDCALL
;
4669 if(This
->createParms
.BehaviorFlags
& WINED3DCREATE_MULTITHREADED
) {
4670 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4672 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4675 checkGLcall("glFlush");
4678 This
->inScene
= FALSE
;
4682 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4683 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4684 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4685 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4686 IWineD3DSwapChain
*swapChain
= NULL
;
4688 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4690 TRACE("(%p) Presenting the frame\n", This
);
4692 for(i
= 0 ; i
< swapchains
; i
++) {
4694 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4695 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4696 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4697 IWineD3DSwapChain_Release(swapChain
);
4703 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4704 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4705 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4706 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4708 GLbitfield glMask
= 0;
4710 CONST WINED3DRECT
* curRect
;
4712 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4713 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4715 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4716 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4717 /* TODO: What about depth stencil buffers without stencil bits? */
4718 return WINED3DERR_INVALIDCALL
;
4721 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4722 * and not the last active one.
4724 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_CLEAR
);
4727 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4728 apply_fbo_state(iface
);
4731 if (Count
> 0 && pRects
) {
4737 /* Only set the values up once, as they are not changing */
4738 if (Flags
& WINED3DCLEAR_STENCIL
) {
4739 glClearStencil(Stencil
);
4740 checkGLcall("glClearStencil");
4741 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4742 glStencilMask(0xFFFFFFFF);
4745 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4746 glDepthMask(GL_TRUE
);
4748 checkGLcall("glClearDepth");
4749 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4750 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4753 if (Flags
& WINED3DCLEAR_TARGET
) {
4754 TRACE("Clearing screen with glClear to color %x\n", Color
);
4755 glClearColor(D3DCOLOR_R(Color
),
4759 checkGLcall("glClearColor");
4761 /* Clear ALL colors! */
4762 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4763 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4767 /* In drawable flag is set below */
4769 if (This
->render_offscreen
) {
4770 glScissor(This
->stateBlock
->viewport
.X
,
4771 This
->stateBlock
->viewport
.Y
,
4772 This
->stateBlock
->viewport
.Width
,
4773 This
->stateBlock
->viewport
.Height
);
4775 glScissor(This
->stateBlock
->viewport
.X
,
4776 (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
-
4777 (This
->stateBlock
->viewport
.Y
+ This
->stateBlock
->viewport
.Height
)),
4778 This
->stateBlock
->viewport
.Width
,
4779 This
->stateBlock
->viewport
.Height
);
4781 checkGLcall("glScissor");
4783 checkGLcall("glClear");
4785 if(!(target
->Flags
& SFLAG_INDRAWABLE
) &&
4786 !(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& This
->render_offscreen
&& target
->Flags
& SFLAG_INTEXTURE
)) {
4788 if(curRect
[0].x1
> 0 || curRect
[0].y1
> 0 ||
4789 curRect
[0].x2
< target
->currentDesc
.Width
||
4790 curRect
[0].y2
< target
->currentDesc
.Height
) {
4791 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4792 blt_to_drawable(This
, target
);
4796 /* Now process each rect in turn */
4797 for (i
= 0; i
< Count
; i
++) {
4798 /* Note gl uses lower left, width/height */
4799 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
, curRect
,
4800 curRect
[i
].x1
, curRect
[i
].y1
, curRect
[i
].x2
, curRect
[i
].y2
,
4801 curRect
[i
].x1
, (target
->currentDesc
.Height
- curRect
[i
].y2
),
4802 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4804 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4805 * The rectangle is not cleared, no error is returned, but further rectanlges are
4806 * still cleared if they are valid
4808 if(curRect
[i
].x1
> curRect
[i
].x2
|| curRect
[i
].y1
> curRect
[i
].y2
) {
4809 TRACE("Rectangle with negative dimensions, ignoring\n");
4813 if(This
->render_offscreen
) {
4814 glScissor(curRect
[i
].x1
, curRect
[i
].y1
,
4815 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4817 glScissor(curRect
[i
].x1
, target
->currentDesc
.Height
- curRect
[i
].y2
,
4818 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4820 checkGLcall("glScissor");
4823 checkGLcall("glClear");
4827 /* Restore the old values (why..?) */
4828 if (Flags
& WINED3DCLEAR_STENCIL
) {
4829 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4831 if (Flags
& WINED3DCLEAR_TARGET
) {
4832 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4833 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4834 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4835 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4836 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4841 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4842 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4844 if(This
->render_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4845 target
->Flags
|= SFLAG_INTEXTURE
;
4846 target
->Flags
&= ~SFLAG_INSYSMEM
;
4848 target
->Flags
|= SFLAG_INDRAWABLE
;
4849 target
->Flags
&= ~(SFLAG_INTEXTURE
| SFLAG_INSYSMEM
);
4857 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4858 UINT PrimitiveCount
) {
4860 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4862 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4863 debug_d3dprimitivetype(PrimitiveType
),
4864 StartVertex
, PrimitiveCount
);
4866 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4867 if(This
->stateBlock
->streamIsUP
) {
4868 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4869 This
->stateBlock
->streamIsUP
= FALSE
;
4872 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4873 This
->stateBlock
->loadBaseVertexIndex
= 0;
4874 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4876 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4877 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4878 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4882 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4883 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4884 WINED3DPRIMITIVETYPE PrimitiveType
,
4885 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4887 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4889 IWineD3DIndexBuffer
*pIB
;
4890 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4893 pIB
= This
->stateBlock
->pIndexData
;
4895 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4896 * without an index buffer set. (The first time at least...)
4897 * D3D8 simply dies, but I doubt it can do much harm to return
4898 * D3DERR_INVALIDCALL there as well. */
4899 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4900 return WINED3DERR_INVALIDCALL
;
4903 if(This
->stateBlock
->streamIsUP
) {
4904 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4905 This
->stateBlock
->streamIsUP
= FALSE
;
4907 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
4909 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
4910 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4911 minIndex
, NumVertices
, startIndex
, primCount
);
4913 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
4914 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
4920 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4921 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4922 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4925 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
4926 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
4931 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4932 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
4933 UINT VertexStreamZeroStride
) {
4934 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4935 IWineD3DVertexBuffer
*vb
;
4937 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
4938 debug_d3dprimitivetype(PrimitiveType
),
4939 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4941 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4942 vb
= This
->stateBlock
->streamSource
[0];
4943 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4944 if(vb
) IWineD3DVertexBuffer_Release(vb
);
4945 This
->stateBlock
->streamOffset
[0] = 0;
4946 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4947 This
->stateBlock
->streamIsUP
= TRUE
;
4948 This
->stateBlock
->loadBaseVertexIndex
= 0;
4950 /* TODO: Only mark dirty if drawing from a different UP address */
4951 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4953 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
4954 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
4956 /* MSDN specifies stream zero settings must be set to NULL */
4957 This
->stateBlock
->streamStride
[0] = 0;
4958 This
->stateBlock
->streamSource
[0] = NULL
;
4960 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4961 * the new stream sources or use UP drawing again
4966 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4967 UINT MinVertexIndex
, UINT NumVertices
,
4968 UINT PrimitiveCount
, CONST
void* pIndexData
,
4969 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
4970 UINT VertexStreamZeroStride
) {
4972 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4973 IWineD3DVertexBuffer
*vb
;
4974 IWineD3DIndexBuffer
*ib
;
4976 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4977 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4978 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
4979 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4981 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
4987 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4988 vb
= This
->stateBlock
->streamSource
[0];
4989 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4990 if(vb
) IWineD3DVertexBuffer_Release(vb
);
4991 This
->stateBlock
->streamIsUP
= TRUE
;
4992 This
->stateBlock
->streamOffset
[0] = 0;
4993 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4995 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4996 This
->stateBlock
->baseVertexIndex
= 0;
4997 This
->stateBlock
->loadBaseVertexIndex
= 0;
4998 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4999 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5000 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5002 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5004 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5005 This
->stateBlock
->streamSource
[0] = NULL
;
5006 This
->stateBlock
->streamStride
[0] = 0;
5007 ib
= This
->stateBlock
->pIndexData
;
5009 IWineD3DIndexBuffer_Release(ib
);
5010 This
->stateBlock
->pIndexData
= NULL
;
5012 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5013 * SetStreamSource to specify a vertex buffer
5019 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5020 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5022 /* Mark the state dirty until we have nicer tracking
5023 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5026 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5027 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5028 This
->stateBlock
->baseVertexIndex
= 0;
5029 This
->up_strided
= DrawPrimStrideData
;
5030 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5031 This
->up_strided
= NULL
;
5035 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5036 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5037 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5039 /* Mark the state dirty until we have nicer tracking
5040 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5043 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5044 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5045 This
->stateBlock
->streamIsUP
= TRUE
;
5046 This
->stateBlock
->baseVertexIndex
= 0;
5047 This
->up_strided
= DrawPrimStrideData
;
5048 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5049 This
->up_strided
= NULL
;
5053 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5054 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5055 * not callable by the app directly no parameter validation checks are needed here.
5057 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5058 WINED3DLOCKED_BOX src
;
5059 WINED3DLOCKED_BOX dst
;
5061 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5063 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5064 * dirtification to improve loading performance.
5066 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5067 if(FAILED(hr
)) return hr
;
5068 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5070 IWineD3DVolume_UnlockBox(pSourceVolume
);
5074 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5076 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5078 IWineD3DVolume_UnlockBox(pSourceVolume
);
5080 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5085 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5086 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5087 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5088 HRESULT hr
= WINED3D_OK
;
5089 WINED3DRESOURCETYPE sourceType
;
5090 WINED3DRESOURCETYPE destinationType
;
5093 /* TODO: think about moving the code into IWineD3DBaseTexture */
5095 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5097 /* verify that the source and destination textures aren't NULL */
5098 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5099 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5100 This
, pSourceTexture
, pDestinationTexture
);
5101 hr
= WINED3DERR_INVALIDCALL
;
5104 if (pSourceTexture
== pDestinationTexture
) {
5105 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5106 This
, pSourceTexture
, pDestinationTexture
);
5107 hr
= WINED3DERR_INVALIDCALL
;
5109 /* Verify that the source and destination textures are the same type */
5110 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5111 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5113 if (sourceType
!= destinationType
) {
5114 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5116 hr
= WINED3DERR_INVALIDCALL
;
5119 /* check that both textures have the identical numbers of levels */
5120 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5121 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5122 hr
= WINED3DERR_INVALIDCALL
;
5125 if (WINED3D_OK
== hr
) {
5127 /* Make sure that the destination texture is loaded */
5128 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5130 /* Update every surface level of the texture */
5131 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5133 switch (sourceType
) {
5134 case WINED3DRTYPE_TEXTURE
:
5136 IWineD3DSurface
*srcSurface
;
5137 IWineD3DSurface
*destSurface
;
5139 for (i
= 0 ; i
< levels
; ++i
) {
5140 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5141 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5142 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5143 IWineD3DSurface_Release(srcSurface
);
5144 IWineD3DSurface_Release(destSurface
);
5145 if (WINED3D_OK
!= hr
) {
5146 WARN("(%p) : Call to update surface failed\n", This
);
5152 case WINED3DRTYPE_CUBETEXTURE
:
5154 IWineD3DSurface
*srcSurface
;
5155 IWineD3DSurface
*destSurface
;
5156 WINED3DCUBEMAP_FACES faceType
;
5158 for (i
= 0 ; i
< levels
; ++i
) {
5159 /* Update each cube face */
5160 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5161 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5162 if (WINED3D_OK
!= hr
) {
5163 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5165 TRACE("Got srcSurface %p\n", srcSurface
);
5167 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5168 if (WINED3D_OK
!= hr
) {
5169 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5171 TRACE("Got desrSurface %p\n", destSurface
);
5173 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5174 IWineD3DSurface_Release(srcSurface
);
5175 IWineD3DSurface_Release(destSurface
);
5176 if (WINED3D_OK
!= hr
) {
5177 WARN("(%p) : Call to update surface failed\n", This
);
5185 case WINED3DRTYPE_VOLUMETEXTURE
:
5187 IWineD3DVolume
*srcVolume
= NULL
;
5188 IWineD3DVolume
*destVolume
= NULL
;
5190 for (i
= 0 ; i
< levels
; ++i
) {
5191 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5192 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5193 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5194 IWineD3DVolume_Release(srcVolume
);
5195 IWineD3DVolume_Release(destVolume
);
5196 if (WINED3D_OK
!= hr
) {
5197 WARN("(%p) : Call to update volume failed\n", This
);
5205 FIXME("(%p) : Unsupported source and destination type\n", This
);
5206 hr
= WINED3DERR_INVALIDCALL
;
5213 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5214 IWineD3DSwapChain
*swapChain
;
5216 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5217 if(hr
== WINED3D_OK
) {
5218 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5219 IWineD3DSwapChain_Release(swapChain
);
5224 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5225 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5226 /* return a sensible default */
5228 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5229 FIXME("(%p) : stub\n", This
);
5233 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5234 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5236 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5237 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5238 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5239 return WINED3DERR_INVALIDCALL
;
5241 for (j
= 0; j
< 256; ++j
) {
5242 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5243 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5244 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5245 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5247 TRACE("(%p) : returning\n", This
);
5251 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5252 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5254 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5255 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5256 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5257 return WINED3DERR_INVALIDCALL
;
5259 for (j
= 0; j
< 256; ++j
) {
5260 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5261 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5262 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5263 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5265 TRACE("(%p) : returning\n", This
);
5269 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5270 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5271 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5272 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5273 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5274 return WINED3DERR_INVALIDCALL
;
5276 /*TODO: stateblocks */
5277 This
->currentPalette
= PaletteNumber
;
5278 TRACE("(%p) : returning\n", This
);
5282 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5283 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5284 if (PaletteNumber
== NULL
) {
5285 WARN("(%p) : returning Invalid Call\n", This
);
5286 return WINED3DERR_INVALIDCALL
;
5288 /*TODO: stateblocks */
5289 *PaletteNumber
= This
->currentPalette
;
5290 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5294 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5295 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5296 static BOOL showFixmes
= TRUE
;
5298 FIXME("(%p) : stub\n", This
);
5302 This
->softwareVertexProcessing
= bSoftware
;
5307 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5308 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5309 static BOOL showFixmes
= TRUE
;
5311 FIXME("(%p) : stub\n", This
);
5314 return This
->softwareVertexProcessing
;
5318 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5319 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5320 IWineD3DSwapChain
*swapChain
;
5323 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5325 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5326 if(hr
== WINED3D_OK
){
5327 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5328 IWineD3DSwapChain_Release(swapChain
);
5330 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5336 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5337 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5338 static BOOL showfixmes
= TRUE
;
5339 if(nSegments
!= 0.0f
) {
5341 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5348 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5349 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5350 static BOOL showfixmes
= TRUE
;
5352 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5358 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5360 /** TODO: remove casts to IWineD3DSurfaceImpl
5361 * NOTE: move code to surface to accomplish this
5362 ****************************************/
5363 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5364 int srcWidth
, srcHeight
;
5365 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5366 WINED3DFORMAT destFormat
, srcFormat
;
5368 int srcLeft
, destLeft
, destTop
;
5369 WINED3DPOOL srcPool
, destPool
;
5371 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5372 glDescriptor
*glDescription
= NULL
;
5375 CONVERT_TYPES convert
= NO_CONVERSION
;
5377 WINED3DSURFACE_DESC winedesc
;
5379 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5380 memset(&winedesc
, 0, sizeof(winedesc
));
5381 winedesc
.Width
= &srcSurfaceWidth
;
5382 winedesc
.Height
= &srcSurfaceHeight
;
5383 winedesc
.Pool
= &srcPool
;
5384 winedesc
.Format
= &srcFormat
;
5386 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5388 winedesc
.Width
= &destSurfaceWidth
;
5389 winedesc
.Height
= &destSurfaceHeight
;
5390 winedesc
.Pool
= &destPool
;
5391 winedesc
.Format
= &destFormat
;
5392 winedesc
.Size
= &destSize
;
5394 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5396 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5397 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5398 return WINED3DERR_INVALIDCALL
;
5401 /* This call loads the opengl surface directly, instead of copying the surface to the
5402 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5403 * copy in sysmem and use regular surface loading.
5405 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5406 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5407 if(convert
!= NO_CONVERSION
) {
5408 return IWineD3DSurface_BltFast(pDestinationSurface
,
5409 pDestPoint
? pDestPoint
->x
: 0,
5410 pDestPoint
? pDestPoint
->y
: 0,
5411 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5414 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5415 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5416 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5418 /* Get the update surface description */
5419 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5422 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5426 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5427 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5428 checkGLcall("glActiveTextureARB");
5431 /* Make sure the surface is loaded and up to date */
5432 IWineD3DSurface_PreLoad(pDestinationSurface
);
5434 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5436 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5437 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5438 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5439 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5440 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5441 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5444 /* This function doesn't support compressed textures
5445 the pitch is just bytesPerPixel * width */
5446 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5447 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5448 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5449 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5451 /* TODO DXT formats */
5453 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5454 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5456 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5458 ,glDescription
->level
5463 ,glDescription
->glFormat
5464 ,glDescription
->glType
5465 ,IWineD3DSurface_GetData(pSourceSurface
)
5469 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5471 /* need to lock the surface to get the data */
5472 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5475 /* TODO: Cube and volume support */
5477 /* not a whole row so we have to do it a line at a time */
5480 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5481 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5483 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5485 glTexSubImage2D(glDescription
->target
5486 ,glDescription
->level
5491 ,glDescription
->glFormat
5492 ,glDescription
->glType
5493 ,data
/* could be quicker using */
5498 } else { /* Full width, so just write out the whole texture */
5500 if (WINED3DFMT_DXT1
== destFormat
||
5501 WINED3DFMT_DXT2
== destFormat
||
5502 WINED3DFMT_DXT3
== destFormat
||
5503 WINED3DFMT_DXT4
== destFormat
||
5504 WINED3DFMT_DXT5
== destFormat
) {
5505 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5506 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5507 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5508 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5509 } if (destFormat
!= srcFormat
) {
5510 FIXME("Updating mixed format compressed texture is not curretly support\n");
5512 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5513 glDescription
->level
,
5514 glDescription
->glFormatInternal
,
5519 IWineD3DSurface_GetData(pSourceSurface
));
5522 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5527 glTexSubImage2D(glDescription
->target
5528 ,glDescription
->level
5533 ,glDescription
->glFormat
5534 ,glDescription
->glType
5535 ,IWineD3DSurface_GetData(pSourceSurface
)
5539 checkGLcall("glTexSubImage2D");
5543 ((IWineD3DSurfaceImpl
*)pDestinationSurface
)->Flags
&= ~SFLAG_INSYSMEM
;
5544 ((IWineD3DSurfaceImpl
*)pDestinationSurface
)->Flags
|= SFLAG_INTEXTURE
;
5545 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
5550 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5551 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5552 struct WineD3DRectPatch
*patch
;
5556 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5558 if(!(Handle
|| pRectPatchInfo
)) {
5559 /* TODO: Write a test for the return value, thus the FIXME */
5560 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5561 return WINED3DERR_INVALIDCALL
;
5565 i
= PATCHMAP_HASHFUNC(Handle
);
5567 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5568 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5569 if(patch
->Handle
== Handle
) {
5576 TRACE("Patch does not exist. Creating a new one\n");
5577 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5578 patch
->Handle
= Handle
;
5579 list_add_head(&This
->patches
[i
], &patch
->entry
);
5581 TRACE("Found existing patch %p\n", patch
);
5584 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5585 * attributes we have to tesselate, read back, and draw. This needs a patch
5586 * management structure instance. Create one.
5588 * A possible improvement is to check if a vertex shader is used, and if not directly
5591 FIXME("Drawing an uncached patch. This is slow\n");
5592 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5595 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5596 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5597 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5599 TRACE("Tesselation density or patch info changed, retesselating\n");
5601 if(pRectPatchInfo
) {
5602 memcpy(&patch
->RectPatchInfo
, pRectPatchInfo
, sizeof(*pRectPatchInfo
));
5604 patch
->numSegs
[0] = pNumSegs
[0];
5605 patch
->numSegs
[1] = pNumSegs
[1];
5606 patch
->numSegs
[2] = pNumSegs
[2];
5607 patch
->numSegs
[3] = pNumSegs
[3];
5609 hr
= tesselate_rectpatch(This
, patch
);
5611 WARN("Patch tesselation failed\n");
5613 /* Do not release the handle to store the params of the patch */
5615 HeapFree(GetProcessHeap(), 0, patch
);
5621 This
->currentPatch
= patch
;
5622 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
5623 This
->currentPatch
= NULL
;
5625 /* Destroy uncached patches */
5627 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5628 HeapFree(GetProcessHeap(), 0, patch
);
5633 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5634 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5635 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5636 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5637 FIXME("(%p) : Stub\n", This
);
5641 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5642 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5644 struct WineD3DRectPatch
*patch
;
5646 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5648 i
= PATCHMAP_HASHFUNC(Handle
);
5649 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5650 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5651 if(patch
->Handle
== Handle
) {
5652 TRACE("Deleting patch %p\n", patch
);
5653 list_remove(&patch
->entry
);
5654 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5655 HeapFree(GetProcessHeap(), 0, patch
);
5660 /* TODO: Write a test for the return value */
5661 FIXME("Attempt to destroy nonexistant patch\n");
5662 return WINED3DERR_INVALIDCALL
;
5665 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5667 IWineD3DSwapChain
*swapchain
;
5669 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5670 if (SUCCEEDED(hr
)) {
5671 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5678 static void bind_fbo(IWineD3DDevice
*iface
, GLenum target
, GLuint
*fbo
) {
5679 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5682 GL_EXTCALL(glGenFramebuffersEXT(1, fbo
));
5683 checkGLcall("glGenFramebuffersEXT()");
5685 GL_EXTCALL(glBindFramebufferEXT(target
, *fbo
));
5686 checkGLcall("glBindFramebuffer()");
5689 static void attach_surface_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, DWORD idx
, IWineD3DSurface
*surface
) {
5690 const IWineD3DSurfaceImpl
*surface_impl
= (IWineD3DSurfaceImpl
*)surface
;
5691 IWineD3DBaseTextureImpl
*texture_impl
;
5692 GLenum texttarget
, target
;
5695 texttarget
= surface_impl
->glDescription
.target
;
5696 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5697 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5699 IWineD3DSurface_PreLoad(surface
);
5701 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5702 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5703 glBindTexture(target
, old_binding
);
5705 /* Update base texture states array */
5706 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
5707 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
5708 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
5709 if (texture_impl
->baseTexture
.bindCount
) {
5710 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
5713 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
5716 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
,
5717 surface_impl
->glDescription
.textureName
, surface_impl
->glDescription
.level
));
5719 checkGLcall("attach_surface_fbo");
5722 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
5723 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5724 IWineD3DSwapChain
*swapchain
;
5726 swapchain
= get_swapchain(surface
);
5730 TRACE("Surface %p is onscreen\n", surface
);
5732 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5733 buffer
= surface_get_gl_buffer(surface
, swapchain
);
5734 glDrawBuffer(buffer
);
5735 checkGLcall("glDrawBuffer()");
5737 TRACE("Surface %p is offscreen\n", surface
);
5738 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
5739 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
5743 glEnable(GL_SCISSOR_TEST
);
5745 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5747 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5748 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5750 checkGLcall("glScissor");
5752 glDisable(GL_SCISSOR_TEST
);
5754 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5756 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5757 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5759 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
5760 glClear(GL_COLOR_BUFFER_BIT
);
5761 checkGLcall("glClear");
5763 if (This
->render_offscreen
) {
5764 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
5766 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5767 checkGLcall("glBindFramebuffer()");
5770 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
5771 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
5772 glDrawBuffer(GL_BACK
);
5773 checkGLcall("glDrawBuffer()");
5777 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5778 unsigned int r
, g
, b
, a
;
5781 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
5782 destfmt
== WINED3DFMT_R8G8B8
)
5785 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5787 a
= (color
& 0xff000000) >> 24;
5788 r
= (color
& 0x00ff0000) >> 16;
5789 g
= (color
& 0x0000ff00) >> 8;
5790 b
= (color
& 0x000000ff) >> 0;
5794 case WINED3DFMT_R5G6B5
:
5795 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5802 TRACE("Returning %08x\n", ret
);
5805 case WINED3DFMT_X1R5G5B5
:
5806 case WINED3DFMT_A1R5G5B5
:
5815 TRACE("Returning %08x\n", ret
);
5819 TRACE("Returning %08x\n", a
);
5822 case WINED3DFMT_X4R4G4B4
:
5823 case WINED3DFMT_A4R4G4B4
:
5832 TRACE("Returning %08x\n", ret
);
5835 case WINED3DFMT_R3G3B2
:
5842 TRACE("Returning %08x\n", ret
);
5845 case WINED3DFMT_X8B8G8R8
:
5846 case WINED3DFMT_A8B8G8R8
:
5851 TRACE("Returning %08x\n", ret
);
5854 case WINED3DFMT_A2R10G10B10
:
5856 r
= (r
* 1024) / 256;
5857 g
= (g
* 1024) / 256;
5858 b
= (b
* 1024) / 256;
5863 TRACE("Returning %08x\n", ret
);
5866 case WINED3DFMT_A2B10G10R10
:
5868 r
= (r
* 1024) / 256;
5869 g
= (g
* 1024) / 256;
5870 b
= (b
* 1024) / 256;
5875 TRACE("Returning %08x\n", ret
);
5879 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5884 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5885 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5886 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5888 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
5890 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5891 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5892 return WINED3DERR_INVALIDCALL
;
5895 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5896 color_fill_fbo(iface
, pSurface
, pRect
, color
);
5899 /* Just forward this to the DirectDraw blitting engine */
5900 memset(&BltFx
, 0, sizeof(BltFx
));
5901 BltFx
.dwSize
= sizeof(BltFx
);
5902 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
5903 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
5907 /* rendertarget and deptth stencil functions */
5908 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5909 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5911 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5912 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5913 return WINED3DERR_INVALIDCALL
;
5916 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5917 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5918 /* Note inc ref on returned surface */
5919 if(*ppRenderTarget
!= NULL
)
5920 IWineD3DSurface_AddRef(*ppRenderTarget
);
5924 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
5925 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5926 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5927 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5928 IWineD3DSwapChainImpl
*Swapchain
;
5931 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
5933 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5934 if(hr
!= WINED3D_OK
) {
5935 ERR("Can't get the swapchain\n");
5939 /* Make sure to release the swapchain */
5940 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5942 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5943 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5944 return WINED3DERR_INVALIDCALL
;
5946 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5947 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5948 return WINED3DERR_INVALIDCALL
;
5951 if(Swapchain
->frontBuffer
!= Front
) {
5952 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5954 if(Swapchain
->frontBuffer
)
5955 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5956 Swapchain
->frontBuffer
= Front
;
5958 if(Swapchain
->frontBuffer
) {
5959 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5963 if(Back
&& !Swapchain
->backBuffer
) {
5964 /* We need memory for the back buffer array - only one back buffer this way */
5965 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
5966 if(!Swapchain
->backBuffer
) {
5967 ERR("Out of memory\n");
5968 return E_OUTOFMEMORY
;
5972 if(Swapchain
->backBuffer
[0] != Back
) {
5973 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
5975 /* What to do about the context here in the case of multithreading? Not sure.
5976 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5979 if(!Swapchain
->backBuffer
[0]) {
5980 /* GL was told to draw to the front buffer at creation,
5983 glDrawBuffer(GL_BACK
);
5984 checkGLcall("glDrawBuffer(GL_BACK)");
5985 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5986 Swapchain
->presentParms
.BackBufferCount
= 1;
5988 /* That makes problems - disable for now */
5989 /* glDrawBuffer(GL_FRONT); */
5990 checkGLcall("glDrawBuffer(GL_FRONT)");
5991 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5992 Swapchain
->presentParms
.BackBufferCount
= 0;
5996 if(Swapchain
->backBuffer
[0])
5997 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5998 Swapchain
->backBuffer
[0] = Back
;
6000 if(Swapchain
->backBuffer
[0]) {
6001 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6003 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6011 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6012 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6013 *ppZStencilSurface
= This
->depthStencilBuffer
;
6014 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6016 if(*ppZStencilSurface
!= NULL
) {
6017 /* Note inc ref on returned surface */
6018 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6021 return WINED3DERR_NOTFOUND
;
6025 /* TODO: Handle stencil attachments */
6026 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
6027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6028 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
6030 TRACE("Set depth stencil to %p\n", depth_stencil
);
6032 if (depth_stencil_impl
) {
6033 if (depth_stencil_impl
->current_renderbuffer
) {
6034 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, depth_stencil_impl
->current_renderbuffer
->id
));
6035 checkGLcall("glFramebufferRenderbufferEXT()");
6037 IWineD3DBaseTextureImpl
*texture_impl
;
6038 GLenum texttarget
, target
;
6039 GLint old_binding
= 0;
6041 texttarget
= depth_stencil_impl
->glDescription
.target
;
6042 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
6043 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6045 IWineD3DSurface_PreLoad(depth_stencil
);
6047 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6048 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6049 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
6050 glBindTexture(target
, old_binding
);
6052 /* Update base texture states array */
6053 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6054 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6055 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6056 if (texture_impl
->baseTexture
.bindCount
) {
6057 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6060 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6063 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
,
6064 depth_stencil_impl
->glDescription
.textureName
, depth_stencil_impl
->glDescription
.level
));
6065 checkGLcall("glFramebufferTexture2DEXT()");
6068 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
6069 checkGLcall("glFramebufferTexture2DEXT()");
6073 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
6074 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6075 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
6077 TRACE("Set render target %u to %p\n", idx
, render_target
);
6080 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, idx
, render_target
);
6081 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
6083 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
6084 checkGLcall("glFramebufferTexture2DEXT()");
6086 This
->draw_buffers
[idx
] = GL_NONE
;
6090 static void check_fbo_status(IWineD3DDevice
*iface
) {
6091 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6094 status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
6095 if (status
== GL_FRAMEBUFFER_COMPLETE_EXT
) {
6096 TRACE("FBO complete\n");
6098 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status
), status
);
6100 /* Dump the FBO attachments */
6101 if (status
== GL_FRAMEBUFFER_UNSUPPORTED_EXT
) {
6102 IWineD3DSurfaceImpl
*attachment
;
6105 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6106 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_color_attachments
[i
];
6108 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i
, attachment
, debug_d3dformat(attachment
->resource
.format
),
6109 attachment
->pow2Width
, attachment
->pow2Height
);
6112 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_depth_attachment
;
6114 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment
, debug_d3dformat(attachment
->resource
.format
),
6115 attachment
->pow2Width
, attachment
->pow2Height
);
6121 static BOOL
depth_mismatch_fbo(IWineD3DDevice
*iface
) {
6122 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6123 IWineD3DSurfaceImpl
*rt_impl
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
6124 IWineD3DSurfaceImpl
*ds_impl
= (IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
;
6126 if (!ds_impl
) return FALSE
;
6128 if (ds_impl
->current_renderbuffer
) {
6129 return (rt_impl
->pow2Width
!= ds_impl
->current_renderbuffer
->width
||
6130 rt_impl
->pow2Height
!= ds_impl
->current_renderbuffer
->height
);
6133 return (rt_impl
->pow2Width
!= ds_impl
->pow2Width
||
6134 rt_impl
->pow2Height
!= ds_impl
->pow2Height
);
6137 void apply_fbo_state(IWineD3DDevice
*iface
) {
6138 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6141 if (This
->render_offscreen
) {
6142 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6144 /* Apply render targets */
6145 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6146 IWineD3DSurface
*render_target
= This
->render_targets
[i
];
6147 if (This
->fbo_color_attachments
[i
] != render_target
) {
6148 set_render_target_fbo(iface
, i
, render_target
);
6149 This
->fbo_color_attachments
[i
] = render_target
;
6153 /* Apply depth targets */
6154 if (This
->fbo_depth_attachment
!= This
->stencilBufferTarget
|| depth_mismatch_fbo(iface
)) {
6155 unsigned int w
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Width
;
6156 unsigned int h
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Height
;
6158 if (This
->stencilBufferTarget
) {
6159 surface_set_compatible_renderbuffer(This
->stencilBufferTarget
, w
, h
);
6161 set_depth_stencil_fbo(iface
, This
->stencilBufferTarget
);
6162 This
->fbo_depth_attachment
= This
->stencilBufferTarget
;
6165 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
6166 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
6167 checkGLcall("glDrawBuffers()");
6169 glDrawBuffer(This
->draw_buffers
[0]);
6170 checkGLcall("glDrawBuffer()");
6173 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6176 check_fbo_status(iface
);
6179 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6180 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6181 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6182 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6183 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6186 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6187 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6188 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6189 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6192 case WINED3DTEXF_LINEAR
:
6193 gl_filter
= GL_LINEAR
;
6197 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6198 case WINED3DTEXF_NONE
:
6199 case WINED3DTEXF_POINT
:
6200 gl_filter
= GL_NEAREST
;
6204 /* Attach src surface to src fbo */
6205 src_swapchain
= get_swapchain(src_surface
);
6206 if (src_swapchain
) {
6209 TRACE("Source surface %p is onscreen\n", src_surface
);
6210 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6213 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6214 buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6215 glReadBuffer(buffer
);
6216 checkGLcall("glReadBuffer()");
6218 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6219 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6221 TRACE("Source surface %p is offscreen\n", src_surface
);
6223 bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->src_fbo
);
6224 attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6225 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6226 checkGLcall("glReadBuffer()");
6230 /* Attach dst surface to dst fbo */
6231 dst_swapchain
= get_swapchain(dst_surface
);
6232 if (dst_swapchain
) {
6235 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6236 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6239 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6240 buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6241 glDrawBuffer(buffer
);
6242 checkGLcall("glDrawBuffer()");
6244 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6245 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6247 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6249 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6250 if(!src_swapchain
) {
6251 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6255 bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6256 attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6257 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6258 checkGLcall("glDrawBuffer()");
6260 glDisable(GL_SCISSOR_TEST
);
6261 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6264 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6265 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6266 checkGLcall("glBlitFramebuffer()");
6268 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6269 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6270 checkGLcall("glBlitFramebuffer()");
6273 if (This
->render_offscreen
) {
6274 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6276 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6277 checkGLcall("glBindFramebuffer()");
6280 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6281 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6282 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6283 glDrawBuffer(GL_BACK
);
6284 checkGLcall("glDrawBuffer()");
6289 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6290 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6291 WINED3DVIEWPORT viewport
;
6293 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6295 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6296 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6297 return WINED3DERR_INVALIDCALL
;
6300 /* MSDN says that null disables the render target
6301 but a device must always be associated with a render target
6302 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6304 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6307 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6308 FIXME("Trying to set render target 0 to NULL\n");
6309 return WINED3DERR_INVALIDCALL
;
6311 if (pRenderTarget
&& !((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
6312 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
);
6313 return WINED3DERR_INVALIDCALL
;
6316 /* If we are trying to set what we already have, don't bother */
6317 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6318 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6321 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6322 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6323 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6325 /* Render target 0 is special */
6326 if(RenderTargetIndex
== 0) {
6327 /* Finally, reset the viewport as the MSDN states. */
6328 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6329 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6332 viewport
.MaxZ
= 1.0f
;
6333 viewport
.MinZ
= 0.0f
;
6334 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6335 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6336 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6338 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6340 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6342 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6343 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6345 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6350 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6351 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6352 HRESULT hr
= WINED3D_OK
;
6353 IWineD3DSurface
*tmp
;
6355 TRACE("(%p) Swapping z-buffer\n",This
);
6357 if (pNewZStencil
== This
->stencilBufferTarget
) {
6358 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6360 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6361 * depending on the renter target implementation being used.
6362 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6363 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6364 * stencil buffer and incure an extra memory overhead
6365 ******************************************************/
6367 tmp
= This
->stencilBufferTarget
;
6368 This
->stencilBufferTarget
= pNewZStencil
;
6369 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
6370 /* should we be calling the parent or the wined3d surface? */
6371 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6372 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6375 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6376 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6377 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6378 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6379 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6386 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6387 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6388 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6389 /* TODO: the use of Impl is deprecated. */
6390 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6391 WINED3DLOCKED_RECT lockedRect
;
6393 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6395 /* some basic validation checks */
6396 if(This
->cursorTexture
) {
6397 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6399 glDeleteTextures(1, &This
->cursorTexture
);
6401 This
->cursorTexture
= 0;
6404 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6405 This
->haveHardwareCursor
= TRUE
;
6407 This
->haveHardwareCursor
= FALSE
;
6410 WINED3DLOCKED_RECT rect
;
6412 /* MSDN: Cursor must be A8R8G8B8 */
6413 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6414 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6415 return WINED3DERR_INVALIDCALL
;
6418 /* MSDN: Cursor must be smaller than the display mode */
6419 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6420 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6421 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
);
6422 return WINED3DERR_INVALIDCALL
;
6425 if (!This
->haveHardwareCursor
) {
6426 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6428 /* Do not store the surface's pointer because the application may
6429 * release it after setting the cursor image. Windows doesn't
6430 * addref the set surface, so we can't do this either without
6431 * creating circular refcount dependencies. Copy out the gl texture
6434 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6435 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6436 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6438 const GlPixelFormatDesc
*glDesc
;
6439 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6440 char *mem
, *bits
= (char *)rect
.pBits
;
6441 GLint intfmt
= glDesc
->glInternal
;
6442 GLint format
= glDesc
->glFormat
;
6443 GLint type
= glDesc
->glType
;
6444 INT height
= This
->cursorHeight
;
6445 INT width
= This
->cursorWidth
;
6446 INT bpp
= tableEntry
->bpp
;
6449 /* Reformat the texture memory (pitch and width can be
6451 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6452 for(i
= 0; i
< height
; i
++)
6453 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6454 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6457 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6458 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6459 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6462 /* Make sure that a proper texture unit is selected */
6463 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6464 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6465 checkGLcall("glActiveTextureARB");
6467 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
6468 /* Create a new cursor texture */
6469 glGenTextures(1, &This
->cursorTexture
);
6470 checkGLcall("glGenTextures");
6471 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6472 checkGLcall("glBindTexture");
6473 /* Copy the bitmap memory into the cursor texture */
6474 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6475 HeapFree(GetProcessHeap(), 0, mem
);
6476 checkGLcall("glTexImage2D");
6478 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6479 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6480 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6487 FIXME("A cursor texture was not returned.\n");
6488 This
->cursorTexture
= 0;
6493 /* Draw a hardware cursor */
6494 ICONINFO cursorInfo
;
6496 /* Create and clear maskBits because it is not needed for
6497 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6499 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6500 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6501 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6502 WINED3DLOCK_NO_DIRTY_UPDATE
|
6503 WINED3DLOCK_READONLY
6505 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6506 pSur
->currentDesc
.Height
);
6508 cursorInfo
.fIcon
= FALSE
;
6509 cursorInfo
.xHotspot
= XHotSpot
;
6510 cursorInfo
.yHotspot
= YHotSpot
;
6511 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6512 pSur
->currentDesc
.Height
, 1,
6514 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6515 pSur
->currentDesc
.Height
, 1,
6516 32, lockedRect
.pBits
);
6517 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6518 /* Create our cursor and clean up. */
6519 cursor
= CreateIconIndirect(&cursorInfo
);
6521 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6522 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6523 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6524 This
->hardwareCursor
= cursor
;
6525 HeapFree(GetProcessHeap(), 0, maskBits
);
6529 This
->xHotSpot
= XHotSpot
;
6530 This
->yHotSpot
= YHotSpot
;
6534 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6535 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6536 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6538 This
->xScreenSpace
= XScreenSpace
;
6539 This
->yScreenSpace
= YScreenSpace
;
6545 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6546 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6547 BOOL oldVisible
= This
->bCursorVisible
;
6550 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6553 * When ShowCursor is first called it should make the cursor appear at the OS's last
6554 * known cursor position. Because of this, some applications just repetitively call
6555 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6558 This
->xScreenSpace
= pt
.x
;
6559 This
->yScreenSpace
= pt
.y
;
6561 if (This
->haveHardwareCursor
) {
6562 This
->bCursorVisible
= bShow
;
6564 SetCursor(This
->hardwareCursor
);
6570 if (This
->cursorTexture
)
6571 This
->bCursorVisible
= bShow
;
6577 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6579 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6580 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6581 switch (This
->state
) {
6584 case WINED3DERR_DEVICELOST
:
6586 ResourceList
*resourceList
= This
->resources
;
6587 while (NULL
!= resourceList
) {
6588 if (((IWineD3DResourceImpl
*)resourceList
->resource
)->resource
.pool
== WINED3DPOOL_DEFAULT
/* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6589 return WINED3DERR_DEVICENOTRESET
;
6590 resourceList
= resourceList
->next
;
6592 return WINED3DERR_DEVICELOST
;
6594 case WINED3DERR_DRIVERINTERNALERROR
:
6595 return WINED3DERR_DRIVERINTERNALERROR
;
6599 return WINED3DERR_DRIVERINTERNALERROR
;
6603 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6604 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6605 /** FIXME: Resource tracking needs to be done,
6606 * The closes we can do to this is set the priorities of all managed textures low
6607 * and then reset them.
6608 ***********************************************************/
6609 FIXME("(%p) : stub\n", This
);
6613 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6614 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6616 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6617 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6618 /* Release the DC */
6619 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6620 DeleteDC(surface
->hDC
);
6621 /* Release the DIB section */
6622 DeleteObject(surface
->dib
.DIBsection
);
6623 surface
->dib
.bitmap_data
= NULL
;
6624 surface
->resource
.allocatedMemory
= NULL
;
6625 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6627 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6628 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6629 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
6630 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6631 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6633 surface
->pow2Width
= surface
->pow2Height
= 1;
6634 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6635 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6637 if(surface
->glDescription
.textureName
) {
6638 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6640 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6642 surface
->glDescription
.textureName
= 0;
6643 surface
->Flags
&= ~SFLAG_CLIENT
;
6645 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6646 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6647 surface
->Flags
|= SFLAG_NONPOW2
;
6649 surface
->Flags
&= ~SFLAG_NONPOW2
;
6651 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
6652 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6655 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6656 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6657 IWineD3DSwapChainImpl
*swapchain
;
6659 BOOL DisplayModeChanged
= FALSE
;
6660 WINED3DDISPLAYMODE mode
;
6661 TRACE("(%p)\n", This
);
6663 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6665 ERR("Failed to get the first implicit swapchain\n");
6669 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6670 * on an existing gl context, so there's no real need for recreation.
6672 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6674 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6676 TRACE("New params:\n");
6677 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6678 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6679 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6680 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6681 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6682 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6683 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6684 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6685 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6686 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6687 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6688 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6689 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6691 /* No special treatment of these parameters. Just store them */
6692 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6693 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6694 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6695 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6697 /* What to do about these? */
6698 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6699 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6700 ERR("Cannot change the back buffer count yet\n");
6702 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6703 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6704 ERR("Cannot change the back buffer format yet\n");
6706 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6707 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6708 ERR("Cannot change the device window yet\n");
6710 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
6711 ERR("What do do about a changed auto depth stencil parameter?\n");
6714 if(pPresentationParameters
->Windowed
) {
6715 mode
.Width
= swapchain
->orig_width
;
6716 mode
.Height
= swapchain
->orig_height
;
6717 mode
.RefreshRate
= 0;
6718 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6720 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6721 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6722 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6723 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6725 SetWindowLongA(swapchain
->win_handle
, GWL_STYLE
, WS_POPUP
);
6726 SetWindowPos(swapchain
->win_handle
, HWND_TOP
, 0, 0,
6727 pPresentationParameters
->BackBufferWidth
,
6728 pPresentationParameters
->BackBufferHeight
, SWP_SHOWWINDOW
| SWP_FRAMECHANGED
);
6731 /* Should Width == 800 && Height == 0 set 800x600? */
6732 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6733 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6734 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6741 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
6742 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
6746 if(!pPresentationParameters
->Windowed
) {
6747 DisplayModeChanged
= TRUE
;
6749 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6750 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6752 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6753 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6754 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6757 /* Now set the new viewport */
6758 IWineD3DDevice_SetViewport(iface
, &vp
);
6761 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6762 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6763 DisplayModeChanged
) {
6765 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6766 if(!pPresentationParameters
->Windowed
) {
6767 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
6770 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6772 /* Switching out of fullscreen mode? First set the original res, then change the window */
6773 if(pPresentationParameters
->Windowed
) {
6774 IWineD3DDevice_SetFullscreen(iface
, FALSE
);
6776 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6779 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6783 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6784 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6785 /** FIXME: always true at the moment **/
6786 if(!bEnableDialogs
) {
6787 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6793 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6794 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6795 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6797 *pParameters
= This
->createParms
;
6801 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST 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 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
6809 IWineD3DSwapChain_Release(swapchain
);
6814 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6815 IWineD3DSwapChain
*swapchain
;
6816 HRESULT hrc
= WINED3D_OK
;
6818 TRACE("Relaying to swapchain\n");
6820 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6821 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6822 IWineD3DSwapChain_Release(swapchain
);
6828 /** ********************************************************
6829 * Notification functions
6830 ** ********************************************************/
6831 /** This function must be called in the release of a resource when ref == 0,
6832 * the contents of resource must still be correct,
6833 * any handels to other resource held by the caller must be closed
6834 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6835 *****************************************************/
6836 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6837 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6838 ResourceList
* resourceList
;
6840 TRACE("(%p) : resource %p\n", This
, resource
);
6841 /* add a new texture to the frot of the linked list */
6842 resourceList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ResourceList
));
6843 resourceList
->resource
= resource
;
6845 /* Get the old head */
6846 resourceList
->next
= This
->resources
;
6848 This
->resources
= resourceList
;
6849 TRACE("Added resource %p with element %p pointing to %p\n", resource
, resourceList
, resourceList
->next
);
6854 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6855 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6856 ResourceList
* resourceList
= NULL
;
6857 ResourceList
* previousResourceList
= NULL
;
6859 TRACE("(%p) : resource %p\n", This
, resource
);
6861 resourceList
= This
->resources
;
6863 while (resourceList
!= NULL
) {
6864 if(resourceList
->resource
== resource
) break;
6865 previousResourceList
= resourceList
;
6866 resourceList
= resourceList
->next
;
6869 if (resourceList
== NULL
) {
6870 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource
);
6873 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList
->resource
, resourceList
, resourceList
->next
, previousResourceList
);
6875 /* make sure we don't leave a hole in the list */
6876 if (previousResourceList
!= NULL
) {
6877 previousResourceList
->next
= resourceList
->next
;
6879 This
->resources
= resourceList
->next
;
6886 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6887 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6890 TRACE("(%p) : resource %p\n", This
, resource
);
6891 switch(IWineD3DResource_GetType(resource
)){
6892 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6893 case WINED3DRTYPE_SURFACE
: {
6896 /* Cleanup any FBO attachments if d3d is enabled */
6897 if(This
->d3d_initialized
) {
6898 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
6899 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
6901 TRACE("Last active render target destroyed\n");
6902 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6903 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6904 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6905 * and the lastActiveRenderTarget member shouldn't matter
6908 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
6909 TRACE("Activating primary back buffer\n");
6910 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
6911 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
6912 /* Single buffering environment */
6913 TRACE("Activating primary front buffer\n");
6914 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
6916 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6917 /* Implicit render target destroyed, that means the device is being destroyed
6918 * whatever we set here, it shouldn't matter
6920 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
6923 /* May happen during ddraw uninitialization */
6924 TRACE("Render target set, but swapchain does not exist!\n");
6925 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
6929 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6930 if (This
->fbo_color_attachments
[i
] == (IWineD3DSurface
*)resource
) {
6931 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6932 set_render_target_fbo(iface
, i
, NULL
);
6933 This
->fbo_color_attachments
[i
] = NULL
;
6936 if (This
->fbo_depth_attachment
== (IWineD3DSurface
*)resource
) {
6937 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6938 set_depth_stencil_fbo(iface
, NULL
);
6939 This
->fbo_depth_attachment
= NULL
;
6945 case WINED3DRTYPE_TEXTURE
:
6946 case WINED3DRTYPE_CUBETEXTURE
:
6947 case WINED3DRTYPE_VOLUMETEXTURE
:
6948 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6949 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6950 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6951 This
->stateBlock
->textures
[counter
] = NULL
;
6953 if (This
->updateStateBlock
!= This
->stateBlock
){
6954 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6955 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6956 This
->updateStateBlock
->textures
[counter
] = NULL
;
6961 case WINED3DRTYPE_VOLUME
:
6962 /* TODO: nothing really? */
6964 case WINED3DRTYPE_VERTEXBUFFER
:
6965 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6968 TRACE("Cleaning up stream pointers\n");
6970 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6971 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6972 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6974 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6975 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6976 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6977 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6978 /* Set changed flag? */
6981 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) */
6982 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6983 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6984 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6987 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6988 else { /* This shouldn't happen */
6989 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6996 case WINED3DRTYPE_INDEXBUFFER
:
6997 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6998 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6999 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7000 This
->updateStateBlock
->pIndexData
= NULL
;
7003 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7004 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7005 This
->stateBlock
->pIndexData
= NULL
;
7011 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7016 /* Remove the resoruce from the resourceStore */
7017 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7019 TRACE("Resource released\n");
7023 /**********************************************************
7024 * IWineD3DDevice VTbl follows
7025 **********************************************************/
7027 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7029 /*** IUnknown methods ***/
7030 IWineD3DDeviceImpl_QueryInterface
,
7031 IWineD3DDeviceImpl_AddRef
,
7032 IWineD3DDeviceImpl_Release
,
7033 /*** IWineD3DDevice methods ***/
7034 IWineD3DDeviceImpl_GetParent
,
7035 /*** Creation methods**/
7036 IWineD3DDeviceImpl_CreateVertexBuffer
,
7037 IWineD3DDeviceImpl_CreateIndexBuffer
,
7038 IWineD3DDeviceImpl_CreateStateBlock
,
7039 IWineD3DDeviceImpl_CreateSurface
,
7040 IWineD3DDeviceImpl_CreateTexture
,
7041 IWineD3DDeviceImpl_CreateVolumeTexture
,
7042 IWineD3DDeviceImpl_CreateVolume
,
7043 IWineD3DDeviceImpl_CreateCubeTexture
,
7044 IWineD3DDeviceImpl_CreateQuery
,
7045 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7046 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7047 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7048 IWineD3DDeviceImpl_CreateVertexShader
,
7049 IWineD3DDeviceImpl_CreatePixelShader
,
7050 IWineD3DDeviceImpl_CreatePalette
,
7051 /*** Odd functions **/
7052 IWineD3DDeviceImpl_Init3D
,
7053 IWineD3DDeviceImpl_Uninit3D
,
7054 IWineD3DDeviceImpl_SetFullscreen
,
7055 IWineD3DDeviceImpl_SetMultithreaded
,
7056 IWineD3DDeviceImpl_EvictManagedResources
,
7057 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7058 IWineD3DDeviceImpl_GetBackBuffer
,
7059 IWineD3DDeviceImpl_GetCreationParameters
,
7060 IWineD3DDeviceImpl_GetDeviceCaps
,
7061 IWineD3DDeviceImpl_GetDirect3D
,
7062 IWineD3DDeviceImpl_GetDisplayMode
,
7063 IWineD3DDeviceImpl_SetDisplayMode
,
7064 IWineD3DDeviceImpl_GetHWND
,
7065 IWineD3DDeviceImpl_SetHWND
,
7066 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7067 IWineD3DDeviceImpl_GetRasterStatus
,
7068 IWineD3DDeviceImpl_GetSwapChain
,
7069 IWineD3DDeviceImpl_Reset
,
7070 IWineD3DDeviceImpl_SetDialogBoxMode
,
7071 IWineD3DDeviceImpl_SetCursorProperties
,
7072 IWineD3DDeviceImpl_SetCursorPosition
,
7073 IWineD3DDeviceImpl_ShowCursor
,
7074 IWineD3DDeviceImpl_TestCooperativeLevel
,
7075 /*** Getters and setters **/
7076 IWineD3DDeviceImpl_SetClipPlane
,
7077 IWineD3DDeviceImpl_GetClipPlane
,
7078 IWineD3DDeviceImpl_SetClipStatus
,
7079 IWineD3DDeviceImpl_GetClipStatus
,
7080 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7081 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7082 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7083 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7084 IWineD3DDeviceImpl_SetFVF
,
7085 IWineD3DDeviceImpl_GetFVF
,
7086 IWineD3DDeviceImpl_SetGammaRamp
,
7087 IWineD3DDeviceImpl_GetGammaRamp
,
7088 IWineD3DDeviceImpl_SetIndices
,
7089 IWineD3DDeviceImpl_GetIndices
,
7090 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7091 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7092 IWineD3DDeviceImpl_SetLight
,
7093 IWineD3DDeviceImpl_GetLight
,
7094 IWineD3DDeviceImpl_SetLightEnable
,
7095 IWineD3DDeviceImpl_GetLightEnable
,
7096 IWineD3DDeviceImpl_SetMaterial
,
7097 IWineD3DDeviceImpl_GetMaterial
,
7098 IWineD3DDeviceImpl_SetNPatchMode
,
7099 IWineD3DDeviceImpl_GetNPatchMode
,
7100 IWineD3DDeviceImpl_SetPaletteEntries
,
7101 IWineD3DDeviceImpl_GetPaletteEntries
,
7102 IWineD3DDeviceImpl_SetPixelShader
,
7103 IWineD3DDeviceImpl_GetPixelShader
,
7104 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7105 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7106 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7107 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7108 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7109 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7110 IWineD3DDeviceImpl_SetRenderState
,
7111 IWineD3DDeviceImpl_GetRenderState
,
7112 IWineD3DDeviceImpl_SetRenderTarget
,
7113 IWineD3DDeviceImpl_GetRenderTarget
,
7114 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7115 IWineD3DDeviceImpl_SetSamplerState
,
7116 IWineD3DDeviceImpl_GetSamplerState
,
7117 IWineD3DDeviceImpl_SetScissorRect
,
7118 IWineD3DDeviceImpl_GetScissorRect
,
7119 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7120 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7121 IWineD3DDeviceImpl_SetStreamSource
,
7122 IWineD3DDeviceImpl_GetStreamSource
,
7123 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7124 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7125 IWineD3DDeviceImpl_SetTexture
,
7126 IWineD3DDeviceImpl_GetTexture
,
7127 IWineD3DDeviceImpl_SetTextureStageState
,
7128 IWineD3DDeviceImpl_GetTextureStageState
,
7129 IWineD3DDeviceImpl_SetTransform
,
7130 IWineD3DDeviceImpl_GetTransform
,
7131 IWineD3DDeviceImpl_SetVertexDeclaration
,
7132 IWineD3DDeviceImpl_GetVertexDeclaration
,
7133 IWineD3DDeviceImpl_SetVertexShader
,
7134 IWineD3DDeviceImpl_GetVertexShader
,
7135 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7136 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7137 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7138 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7139 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7140 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7141 IWineD3DDeviceImpl_SetViewport
,
7142 IWineD3DDeviceImpl_GetViewport
,
7143 IWineD3DDeviceImpl_MultiplyTransform
,
7144 IWineD3DDeviceImpl_ValidateDevice
,
7145 IWineD3DDeviceImpl_ProcessVertices
,
7146 /*** State block ***/
7147 IWineD3DDeviceImpl_BeginStateBlock
,
7148 IWineD3DDeviceImpl_EndStateBlock
,
7149 /*** Scene management ***/
7150 IWineD3DDeviceImpl_BeginScene
,
7151 IWineD3DDeviceImpl_EndScene
,
7152 IWineD3DDeviceImpl_Present
,
7153 IWineD3DDeviceImpl_Clear
,
7155 IWineD3DDeviceImpl_DrawPrimitive
,
7156 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7157 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7158 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7159 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7160 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7161 IWineD3DDeviceImpl_DrawRectPatch
,
7162 IWineD3DDeviceImpl_DrawTriPatch
,
7163 IWineD3DDeviceImpl_DeletePatch
,
7164 IWineD3DDeviceImpl_ColorFill
,
7165 IWineD3DDeviceImpl_UpdateTexture
,
7166 IWineD3DDeviceImpl_UpdateSurface
,
7167 IWineD3DDeviceImpl_GetFrontBufferData
,
7168 /*** object tracking ***/
7169 IWineD3DDeviceImpl_ResourceReleased
7173 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7174 WINED3DRS_ALPHABLENDENABLE
,
7175 WINED3DRS_ALPHAFUNC
,
7176 WINED3DRS_ALPHAREF
,
7177 WINED3DRS_ALPHATESTENABLE
,
7179 WINED3DRS_COLORWRITEENABLE
,
7180 WINED3DRS_DESTBLEND
,
7181 WINED3DRS_DITHERENABLE
,
7182 WINED3DRS_FILLMODE
,
7183 WINED3DRS_FOGDENSITY
,
7185 WINED3DRS_FOGSTART
,
7186 WINED3DRS_LASTPIXEL
,
7187 WINED3DRS_SHADEMODE
,
7188 WINED3DRS_SRCBLEND
,
7189 WINED3DRS_STENCILENABLE
,
7190 WINED3DRS_STENCILFAIL
,
7191 WINED3DRS_STENCILFUNC
,
7192 WINED3DRS_STENCILMASK
,
7193 WINED3DRS_STENCILPASS
,
7194 WINED3DRS_STENCILREF
,
7195 WINED3DRS_STENCILWRITEMASK
,
7196 WINED3DRS_STENCILZFAIL
,
7197 WINED3DRS_TEXTUREFACTOR
,
7208 WINED3DRS_ZWRITEENABLE
7211 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7212 WINED3DTSS_ADDRESSW
,
7213 WINED3DTSS_ALPHAARG0
,
7214 WINED3DTSS_ALPHAARG1
,
7215 WINED3DTSS_ALPHAARG2
,
7216 WINED3DTSS_ALPHAOP
,
7217 WINED3DTSS_BUMPENVLOFFSET
,
7218 WINED3DTSS_BUMPENVLSCALE
,
7219 WINED3DTSS_BUMPENVMAT00
,
7220 WINED3DTSS_BUMPENVMAT01
,
7221 WINED3DTSS_BUMPENVMAT10
,
7222 WINED3DTSS_BUMPENVMAT11
,
7223 WINED3DTSS_COLORARG0
,
7224 WINED3DTSS_COLORARG1
,
7225 WINED3DTSS_COLORARG2
,
7226 WINED3DTSS_COLOROP
,
7227 WINED3DTSS_RESULTARG
,
7228 WINED3DTSS_TEXCOORDINDEX
,
7229 WINED3DTSS_TEXTURETRANSFORMFLAGS
7232 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7233 WINED3DSAMP_ADDRESSU
,
7234 WINED3DSAMP_ADDRESSV
,
7235 WINED3DSAMP_ADDRESSW
,
7236 WINED3DSAMP_BORDERCOLOR
,
7237 WINED3DSAMP_MAGFILTER
,
7238 WINED3DSAMP_MINFILTER
,
7239 WINED3DSAMP_MIPFILTER
,
7240 WINED3DSAMP_MIPMAPLODBIAS
,
7241 WINED3DSAMP_MAXMIPLEVEL
,
7242 WINED3DSAMP_MAXANISOTROPY
,
7243 WINED3DSAMP_SRGBTEXTURE
,
7244 WINED3DSAMP_ELEMENTINDEX
7247 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7249 WINED3DRS_AMBIENTMATERIALSOURCE
,
7250 WINED3DRS_CLIPPING
,
7251 WINED3DRS_CLIPPLANEENABLE
,
7252 WINED3DRS_COLORVERTEX
,
7253 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7254 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7255 WINED3DRS_FOGDENSITY
,
7257 WINED3DRS_FOGSTART
,
7258 WINED3DRS_FOGTABLEMODE
,
7259 WINED3DRS_FOGVERTEXMODE
,
7260 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7261 WINED3DRS_LIGHTING
,
7262 WINED3DRS_LOCALVIEWER
,
7263 WINED3DRS_MULTISAMPLEANTIALIAS
,
7264 WINED3DRS_MULTISAMPLEMASK
,
7265 WINED3DRS_NORMALIZENORMALS
,
7266 WINED3DRS_PATCHEDGESTYLE
,
7267 WINED3DRS_POINTSCALE_A
,
7268 WINED3DRS_POINTSCALE_B
,
7269 WINED3DRS_POINTSCALE_C
,
7270 WINED3DRS_POINTSCALEENABLE
,
7271 WINED3DRS_POINTSIZE
,
7272 WINED3DRS_POINTSIZE_MAX
,
7273 WINED3DRS_POINTSIZE_MIN
,
7274 WINED3DRS_POINTSPRITEENABLE
,
7275 WINED3DRS_RANGEFOGENABLE
,
7276 WINED3DRS_SPECULARMATERIALSOURCE
,
7277 WINED3DRS_TWEENFACTOR
,
7278 WINED3DRS_VERTEXBLEND
,
7279 WINED3DRS_CULLMODE
,
7283 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7284 WINED3DTSS_TEXCOORDINDEX
,
7285 WINED3DTSS_TEXTURETRANSFORMFLAGS
7288 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7289 WINED3DSAMP_DMAPOFFSET
7292 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7293 DWORD rep
= StateTable
[state
].representative
;
7297 WineD3DContext
*context
;
7300 for(i
= 0; i
< This
->numContexts
; i
++) {
7301 context
= This
->contexts
[i
];
7302 if(isStateDirty(context
, rep
)) continue;
7304 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7307 context
->isStateDirty
[idx
] |= (1 << shift
);