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; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
139 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
140 if (IsEqualGUID(riid
, &IID_IUnknown
)
141 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
142 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
143 IUnknown_AddRef(iface
);
148 return E_NOINTERFACE
;
151 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
152 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
153 ULONG refCount
= InterlockedIncrement(&This
->ref
);
155 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
159 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
161 ULONG refCount
= InterlockedDecrement(&This
->ref
);
163 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->src_fbo
));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->dst_fbo
));
176 if (This
->glsl_program_lookup
) hash_table_destroy(This
->glsl_program_lookup
);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This
->resources
)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
184 dumpResources(&This
->resources
);
187 if(This
->contexts
) ERR("Context array not freed!\n");
188 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
189 This
->haveHardwareCursor
= FALSE
;
191 IWineD3D_Release(This
->wineD3D
);
192 This
->wineD3D
= NULL
;
193 HeapFree(GetProcessHeap(), 0, This
);
194 TRACE("Freed device %p\n", This
);
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
204 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
205 *pParent
= This
->parent
;
206 IUnknown_AddRef(This
->parent
);
210 static void CreateVBO(IWineD3DVertexBufferImpl
*object
) {
211 IWineD3DDeviceImpl
*This
= object
->resource
.wineD3DDevice
; /* Needed for GL_EXTCALL */
212 GLenum error
, glUsage
;
213 DWORD vboUsage
= object
->resource
.usage
;
214 if(object
->Flags
& VBFLAG_VBOCREATEFAIL
) {
215 WARN("Creating a vbo failed once, not trying again\n");
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object
, debug_d3dusage(vboUsage
));
221 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
222 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
225 /* Make sure that the gl error is cleared. Do not use checkGLcall
226 * here because checkGLcall just prints a fixme and continues. However,
227 * if an error during VBO creation occurs we can fall back to non-vbo operation
228 * with full functionality(but performance loss)
230 while(glGetError() != GL_NO_ERROR
);
232 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
233 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
234 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
235 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
236 * to check if the rhw and color values are in the correct format.
239 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
240 error
= glGetError();
241 if(object
->vbo
== 0 || error
!= GL_NO_ERROR
) {
242 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error
), error
);
246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, object
->vbo
));
247 error
= glGetError();
248 if(error
!= GL_NO_ERROR
) {
249 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error
), error
);
253 /* Don't use static, because dx apps tend to update the buffer
254 * quite often even if they specify 0 usage. Because we always keep the local copy
255 * we never read from the vbo and can create a write only opengl buffer.
257 switch(vboUsage
& (WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
) ) {
258 case WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
:
259 case WINED3DUSAGE_DYNAMIC
:
260 TRACE("Gl usage = GL_STREAM_DRAW\n");
261 glUsage
= GL_STREAM_DRAW_ARB
;
263 case WINED3DUSAGE_WRITEONLY
:
265 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
266 glUsage
= GL_DYNAMIC_DRAW_ARB
;
270 /* Reserve memory for the buffer. The amount of data won't change
271 * so we are safe with calling glBufferData once with a NULL ptr and
272 * calling glBufferSubData on updates
274 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
275 error
= glGetError();
276 if(error
!= GL_NO_ERROR
) {
277 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error
), error
);
285 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
286 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
287 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
289 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
294 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
295 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
297 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
298 IWineD3DVertexBufferImpl
*object
;
299 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
300 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
304 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
305 *ppVertexBuffer
= NULL
;
306 return WINED3DERR_INVALIDCALL
;
307 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
308 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
309 * anyway, SCRATCH vertex buffers aren't useable anywhere
311 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
312 *ppVertexBuffer
= NULL
;
313 return WINED3DERR_INVALIDCALL
;
316 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
318 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
319 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
323 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
324 * drawStridedFast (half-life 2).
326 * Basically converting the vertices in the buffer is quite expensive, and observations
327 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
328 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
330 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
331 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
332 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
333 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
335 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
336 * more. In this call we can convert dx7 buffers too.
338 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
339 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
) && Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) &&
340 (dxVersion
> 7 || !conv
) ) {
346 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
347 GLenum error
, glUsage
;
348 TRACE("Creating VBO for Index Buffer %p\n", object
);
350 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
351 * restored on the next draw
353 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
355 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
356 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
361 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
362 error
= glGetError();
363 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
364 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
368 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
369 error
= glGetError();
370 if(error
!= GL_NO_ERROR
) {
371 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
375 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
376 * copy no readback will be needed
378 glUsage
= GL_STATIC_DRAW_ARB
;
379 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
380 error
= glGetError();
381 if(error
!= GL_NO_ERROR
) {
382 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
386 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
390 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
391 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
396 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
397 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
398 HANDLE
*sharedHandle
, IUnknown
*parent
) {
399 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
400 IWineD3DIndexBufferImpl
*object
;
401 TRACE("(%p) Creating index buffer\n", This
);
403 /* Allocate the storage for the device */
404 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
406 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
407 CreateIndexBufferVBO(This
, object
);
410 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
411 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
412 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
417 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
419 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
420 IWineD3DStateBlockImpl
*object
;
424 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
425 object
->blockType
= Type
;
427 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
428 list_init(&object
->lightMap
[i
]);
431 /* Special case - Used during initialization to produce a placeholder stateblock
432 so other functions called can update a state block */
433 if (Type
== WINED3DSBT_INIT
) {
434 /* Don't bother increasing the reference count otherwise a device will never
435 be freed due to circular dependencies */
439 temp_result
= allocate_shader_constants(object
);
440 if (WINED3D_OK
!= temp_result
)
443 /* Otherwise, might as well set the whole state block to the appropriate values */
444 if (This
->stateBlock
!= NULL
)
445 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
447 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
449 /* Reset the ref and type after kludging it */
450 object
->wineD3DDevice
= This
;
452 object
->blockType
= Type
;
454 TRACE("Updating changed flags appropriate for type %d\n", Type
);
456 if (Type
== WINED3DSBT_ALL
) {
458 TRACE("ALL => Pretend everything has changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
461 /* Lights are not part of the changed / set structure */
462 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
464 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
465 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
466 light
->changed
= TRUE
;
467 light
->enabledChanged
= TRUE
;
470 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
471 object
->contained_render_states
[j
- 1] = j
;
473 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
474 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
475 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
476 object
->contained_transform_states
[j
- 1] = j
;
478 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
479 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
480 object
->contained_vs_consts_f
[j
] = j
;
482 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
483 for(j
= 0; j
< MAX_CONST_I
; j
++) {
484 object
->contained_vs_consts_i
[j
] = j
;
486 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
487 for(j
= 0; j
< MAX_CONST_B
; j
++) {
488 object
->contained_vs_consts_b
[j
] = j
;
490 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
491 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
492 object
->contained_ps_consts_f
[j
] = j
;
494 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
495 for(j
= 0; j
< MAX_CONST_I
; j
++) {
496 object
->contained_ps_consts_i
[j
] = j
;
498 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
499 for(j
= 0; j
< MAX_CONST_B
; j
++) {
500 object
->contained_ps_consts_b
[j
] = j
;
502 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
503 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
504 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
505 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
506 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
507 object
->num_contained_tss_states
++;
510 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
511 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
512 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
513 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
514 object
->num_contained_sampler_states
++;
518 for(i
= 0; i
< MAX_STREAMS
; i
++) {
519 if(object
->streamSource
[i
]) {
520 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
523 if(object
->pIndexData
) {
524 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
526 if(object
->vertexShader
) {
527 IWineD3DVertexShader_AddRef(object
->vertexShader
);
529 if(object
->pixelShader
) {
530 IWineD3DPixelShader_AddRef(object
->pixelShader
);
533 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
535 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
536 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
538 object
->changed
.pixelShader
= TRUE
;
540 /* Pixel Shader Constants */
541 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
542 object
->contained_ps_consts_f
[i
] = i
;
543 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
545 object
->num_contained_ps_consts_f
= GL_LIMITS(vshader_constantsF
);
546 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
547 object
->contained_ps_consts_b
[i
] = i
;
548 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
550 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
551 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
552 object
->contained_ps_consts_i
[i
] = i
;
553 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
555 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
557 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
558 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
559 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
561 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
562 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
563 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
564 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
565 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
566 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
567 object
->num_contained_tss_states
++;
570 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
571 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
572 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
573 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
574 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
575 object
->num_contained_sampler_states
++;
578 if(object
->pixelShader
) {
579 IWineD3DPixelShader_AddRef(object
->pixelShader
);
582 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
583 * on them. This makes releasing the buffer easier
585 for(i
= 0; i
< MAX_STREAMS
; i
++) {
586 object
->streamSource
[i
] = NULL
;
588 object
->pIndexData
= NULL
;
589 object
->vertexShader
= NULL
;
591 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
593 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
594 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
596 object
->changed
.vertexShader
= TRUE
;
598 /* Vertex Shader Constants */
599 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
600 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
601 object
->contained_vs_consts_f
[i
] = i
;
603 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
604 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
605 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
606 object
->contained_vs_consts_b
[i
] = i
;
608 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
609 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
610 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
611 object
->contained_vs_consts_i
[i
] = i
;
613 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
614 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
615 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
616 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
618 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
619 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
620 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
621 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
622 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
623 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
624 object
->num_contained_tss_states
++;
627 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
628 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
629 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
630 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
631 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
632 object
->num_contained_sampler_states
++;
636 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
638 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
639 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
640 light
->changed
= TRUE
;
641 light
->enabledChanged
= TRUE
;
645 for(i
= 0; i
< MAX_STREAMS
; i
++) {
646 if(object
->streamSource
[i
]) {
647 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
650 if(object
->vertexShader
) {
651 IWineD3DVertexShader_AddRef(object
->vertexShader
);
653 object
->pIndexData
= NULL
;
654 object
->pixelShader
= NULL
;
656 FIXME("Unrecognized state block type %d\n", Type
);
659 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
663 /* ************************************
665 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
668 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
670 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.
672 ******************************** */
674 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
) {
675 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
676 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
677 unsigned int Size
= 1;
678 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, NULL
, NULL
);
679 TRACE("(%p) Create surface\n",This
);
681 /** FIXME: Check ranges on the inputs are valid
684 * [in] Quality level. The valid range is between zero and one less than the level
685 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
686 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
687 * values of paired render targets, depth stencil surfaces, and the MultiSample type
689 *******************************/
694 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
696 * If this flag is set, the contents of the depth stencil buffer will be
697 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
698 * with a different depth surface.
700 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
701 ***************************/
703 if(MultisampleQuality
< 0) {
704 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
705 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
708 if(MultisampleQuality
> 0) {
709 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
710 MultisampleQuality
=0;
713 /** FIXME: Check that the format is supported
715 *******************************/
717 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
718 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
720 *********************************/
721 if (WINED3DFMT_UNKNOWN
== Format
) {
723 } else if (Format
== WINED3DFMT_DXT1
) {
724 /* DXT1 is half byte per pixel */
725 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
727 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
728 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
729 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
731 /* The pitch is a multiple of 4 bytes */
732 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
736 /** Create and initialise the surface resource **/
737 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
738 /* "Standalone" surface */
739 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
741 object
->currentDesc
.Width
= Width
;
742 object
->currentDesc
.Height
= Height
;
743 object
->currentDesc
.MultiSampleType
= MultiSample
;
744 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
745 object
->glDescription
.level
= Level
;
749 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
750 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
751 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
754 if (WINED3DFMT_UNKNOWN
!= Format
) {
755 object
->bytesPerPixel
= tableEntry
->bpp
;
757 object
->bytesPerPixel
= 0;
760 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
762 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
764 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
765 * this function is too deep to need to care about things like this.
766 * Levels need to be checked too, and possibly Type since they all affect what can be done.
767 * ****************************************/
769 case WINED3DPOOL_SCRATCH
:
771 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
772 "which are mutually exclusive, setting lockable to TRUE\n");
775 case WINED3DPOOL_SYSTEMMEM
:
776 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
777 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
778 case WINED3DPOOL_MANAGED
:
779 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
780 "Usage of DYNAMIC which are mutually exclusive, not doing "
781 "anything just telling you.\n");
783 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
784 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
785 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
786 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
789 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
793 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
794 FIXME("Trying to create a render target that isn't in the default pool\n");
797 /* mark the texture as dirty so that it gets loaded first time around*/
798 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
799 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
800 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
801 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
803 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
804 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
805 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
807 /* Look at the implementation and set the correct Vtable */
810 /* Check if a 3D adapter is available when creating gl surfaces */
812 ERR("OpenGL surfaces are not available without opengl\n");
813 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
814 HeapFree(GetProcessHeap(), 0, object
);
815 return WINED3DERR_NOTAVAILABLE
;
820 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
824 /* To be sure to catch this */
825 ERR("Unknown requested surface implementation %d!\n", Impl
);
826 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
827 return WINED3DERR_INVALIDCALL
;
830 list_init(&object
->renderbuffers
);
832 /* Call the private setup routine */
833 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
837 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
838 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
839 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
840 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
842 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
843 IWineD3DTextureImpl
*object
;
848 unsigned int pow2Width
;
849 unsigned int pow2Height
;
850 const GlPixelFormatDesc
*glDesc
;
851 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
854 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
855 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
856 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
858 /* TODO: It should only be possible to create textures for formats
859 that are reported as supported */
860 if (WINED3DFMT_UNKNOWN
>= Format
) {
861 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
862 return WINED3DERR_INVALIDCALL
;
865 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
866 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
867 object
->width
= Width
;
868 object
->height
= Height
;
870 /** Non-power2 support **/
871 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
875 /* Find the nearest pow2 match */
876 pow2Width
= pow2Height
= 1;
877 while (pow2Width
< Width
) pow2Width
<<= 1;
878 while (pow2Height
< Height
) pow2Height
<<= 1;
880 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
882 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
883 HeapFree(GetProcessHeap(), 0, object
);
885 return WINED3DERR_INVALIDCALL
;
892 /** FIXME: add support for real non-power-two if it's provided by the video card **/
893 /* Precalculated scaling for 'faked' non power of two texture coords */
894 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
895 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
896 object
->baseTexture
.pow2Matrix
[10] = 1.0;
897 object
->baseTexture
.pow2Matrix
[15] = 1.0;
898 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
900 /* Calculate levels for mip mapping */
901 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
902 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
903 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
904 return WINED3DERR_INVALIDCALL
;
907 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
908 return WINED3DERR_INVALIDCALL
;
910 object
->baseTexture
.levels
= 1;
911 } else if (Levels
== 0) {
912 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
913 object
->baseTexture
.levels
++;
916 while (tmpW
> 1 || tmpH
> 1) {
917 tmpW
= max(1, tmpW
>> 1);
918 tmpH
= max(1, tmpH
>> 1);
919 object
->baseTexture
.levels
++;
921 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
924 /* Generate all the surfaces */
927 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
929 /* use the callback to create the texture surface */
930 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
931 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
932 FIXME("Failed to create surface %p\n", object
);
934 object
->surfaces
[i
] = NULL
;
935 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
941 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
942 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
943 /* calculate the next mipmap level */
944 tmpW
= max(1, tmpW
>> 1);
945 tmpH
= max(1, tmpH
>> 1);
947 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
949 TRACE("(%p) : Created texture %p\n", This
, object
);
953 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
954 UINT Width
, UINT Height
, UINT Depth
,
955 UINT Levels
, DWORD Usage
,
956 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
957 IWineD3DVolumeTexture
**ppVolumeTexture
,
958 HANDLE
*pSharedHandle
, IUnknown
*parent
,
959 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
961 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
962 IWineD3DVolumeTextureImpl
*object
;
967 const GlPixelFormatDesc
*glDesc
;
969 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
971 /* TODO: It should only be possible to create textures for formats
972 that are reported as supported */
973 if (WINED3DFMT_UNKNOWN
>= Format
) {
974 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
975 return WINED3DERR_INVALIDCALL
;
977 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
978 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
979 return WINED3DERR_INVALIDCALL
;
982 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
983 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
985 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
986 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
988 object
->width
= Width
;
989 object
->height
= Height
;
990 object
->depth
= Depth
;
992 /* Is NP2 support for volumes needed? */
993 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
994 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
995 object
->baseTexture
.pow2Matrix
[10] = 1.0;
996 object
->baseTexture
.pow2Matrix
[15] = 1.0;
998 /* Calculate levels for mip mapping */
999 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1000 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1001 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1002 return WINED3DERR_INVALIDCALL
;
1005 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1006 return WINED3DERR_INVALIDCALL
;
1009 } else if (Levels
== 0) {
1010 object
->baseTexture
.levels
++;
1014 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
1015 tmpW
= max(1, tmpW
>> 1);
1016 tmpH
= max(1, tmpH
>> 1);
1017 tmpD
= max(1, tmpD
>> 1);
1018 object
->baseTexture
.levels
++;
1020 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1023 /* Generate all the surfaces */
1028 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1031 /* Create the volume */
1032 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
1033 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
1036 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
1037 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
1038 *ppVolumeTexture
= NULL
;
1042 /* Set its container to this object */
1043 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1045 /* calcualte the next mipmap level */
1046 tmpW
= max(1, tmpW
>> 1);
1047 tmpH
= max(1, tmpH
>> 1);
1048 tmpD
= max(1, tmpD
>> 1);
1050 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1052 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1053 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1057 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1058 UINT Width
, UINT Height
, UINT Depth
,
1060 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1061 IWineD3DVolume
** ppVolume
,
1062 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1064 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1065 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1066 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1068 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1069 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1070 return WINED3DERR_INVALIDCALL
;
1073 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1075 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1076 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1078 object
->currentDesc
.Width
= Width
;
1079 object
->currentDesc
.Height
= Height
;
1080 object
->currentDesc
.Depth
= Depth
;
1081 object
->bytesPerPixel
= formatDesc
->bpp
;
1083 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1084 object
->lockable
= TRUE
;
1085 object
->locked
= FALSE
;
1086 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1087 object
->dirty
= TRUE
;
1089 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1092 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1093 UINT Levels
, DWORD Usage
,
1094 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1095 IWineD3DCubeTexture
**ppCubeTexture
,
1096 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1097 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1099 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1100 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1104 unsigned int pow2EdgeLength
= EdgeLength
;
1105 const GlPixelFormatDesc
*glDesc
;
1106 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1108 /* TODO: It should only be possible to create textures for formats
1109 that are reported as supported */
1110 if (WINED3DFMT_UNKNOWN
>= Format
) {
1111 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1112 return WINED3DERR_INVALIDCALL
;
1115 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1116 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1117 return WINED3DERR_INVALIDCALL
;
1120 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1121 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1123 TRACE("(%p) Create Cube Texture\n", This
);
1125 /** Non-power2 support **/
1127 /* Find the nearest pow2 match */
1129 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1131 object
->edgeLength
= EdgeLength
;
1132 /* TODO: support for native non-power 2 */
1133 /* Precalculated scaling for 'faked' non power of two texture coords */
1134 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1135 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1136 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1137 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1139 /* Calculate levels for mip mapping */
1140 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1141 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1142 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1143 HeapFree(GetProcessHeap(), 0, object
);
1144 *ppCubeTexture
= NULL
;
1146 return WINED3DERR_INVALIDCALL
;
1149 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1150 HeapFree(GetProcessHeap(), 0, object
);
1151 *ppCubeTexture
= NULL
;
1153 return WINED3DERR_INVALIDCALL
;
1156 } else if (Levels
== 0) {
1157 object
->baseTexture
.levels
++;
1160 tmpW
= max(1, tmpW
>> 1);
1161 object
->baseTexture
.levels
++;
1163 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1166 /* Generate all the surfaces */
1168 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1170 /* Create the 6 faces */
1171 for (j
= 0; j
< 6; j
++) {
1173 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1174 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1176 if(hr
!= WINED3D_OK
) {
1180 for (l
= 0; l
< j
; l
++) {
1181 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1183 for (k
= 0; k
< i
; k
++) {
1184 for (l
= 0; l
< 6; l
++) {
1185 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1189 FIXME("(%p) Failed to create surface\n",object
);
1190 HeapFree(GetProcessHeap(),0,object
);
1191 *ppCubeTexture
= NULL
;
1194 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1195 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1197 tmpW
= max(1, tmpW
>> 1);
1199 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1201 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1202 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1206 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1207 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1208 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1209 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1211 /* Just a check to see if we support this type of query */
1213 case WINED3DQUERYTYPE_OCCLUSION
:
1214 TRACE("(%p) occlusion query\n", This
);
1215 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1218 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1221 case WINED3DQUERYTYPE_EVENT
:
1222 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1223 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1224 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1226 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1231 case WINED3DQUERYTYPE_VCACHE
:
1232 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1233 case WINED3DQUERYTYPE_VERTEXSTATS
:
1234 case WINED3DQUERYTYPE_TIMESTAMP
:
1235 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1236 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1237 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1238 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1239 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1240 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1241 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1242 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1244 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1246 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1250 D3DCREATEOBJECTINSTANCE(object
, Query
)
1251 object
->type
= Type
;
1252 /* allocated the 'extended' data based on the type of query requested */
1254 case WINED3DQUERYTYPE_OCCLUSION
:
1255 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1256 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1258 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1259 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1260 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1263 case WINED3DQUERYTYPE_EVENT
:
1264 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1265 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1267 if(GL_SUPPORT(APPLE_FENCE
)) {
1268 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1269 checkGLcall("glGenFencesAPPLE");
1270 } else if(GL_SUPPORT(NV_FENCE
)) {
1271 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1272 checkGLcall("glGenFencesNV");
1276 case WINED3DQUERYTYPE_VCACHE
:
1277 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1278 case WINED3DQUERYTYPE_VERTEXSTATS
:
1279 case WINED3DQUERYTYPE_TIMESTAMP
:
1280 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1281 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1282 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1283 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1284 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1285 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1286 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1287 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1289 object
->extendedData
= 0;
1290 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1292 TRACE("(%p) : Created Query %p\n", This
, object
);
1296 /*****************************************************************************
1297 * IWineD3DDeviceImpl_SetupFullscreenWindow
1299 * Helper function that modifies a HWND's Style and ExStyle for proper
1303 * iface: Pointer to the IWineD3DDevice interface
1304 * window: Window to setup
1306 *****************************************************************************/
1307 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1308 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1310 LONG style
, exStyle
;
1311 /* Don't do anything if an original style is stored.
1312 * That shouldn't happen
1314 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1315 if (This
->style
|| This
->exStyle
) {
1316 ERR("(%p): Want to change the window parameters of HWND %p, but "
1317 "another style is stored for restoration afterwards\n", This
, window
);
1320 /* Get the parameters and save them */
1321 style
= GetWindowLongW(window
, GWL_STYLE
);
1322 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1323 This
->style
= style
;
1324 This
->exStyle
= exStyle
;
1326 /* Filter out window decorations */
1327 style
&= ~WS_CAPTION
;
1328 style
&= ~WS_THICKFRAME
;
1329 exStyle
&= ~WS_EX_WINDOWEDGE
;
1330 exStyle
&= ~WS_EX_CLIENTEDGE
;
1332 /* Make sure the window is managed, otherwise we won't get keyboard input */
1333 style
|= WS_POPUP
| WS_SYSMENU
;
1335 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1336 This
->style
, This
->exStyle
, style
, exStyle
);
1338 SetWindowLongW(window
, GWL_STYLE
, style
);
1339 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1341 /* Inform the window about the update. */
1342 SetWindowPos(window
, HWND_TOP
, 0, 0,
1343 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1344 ShowWindow(window
, SW_NORMAL
);
1347 /*****************************************************************************
1348 * IWineD3DDeviceImpl_RestoreWindow
1350 * Helper function that restores a windows' properties when taking it out
1351 * of fullscreen mode
1354 * iface: Pointer to the IWineD3DDevice interface
1355 * window: Window to setup
1357 *****************************************************************************/
1358 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1361 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1362 * switch, do nothing
1364 if (!This
->style
&& !This
->exStyle
) return;
1366 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1367 This
, window
, This
->style
, This
->exStyle
);
1369 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1370 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1372 /* Delete the old values */
1376 /* Inform the window about the update */
1377 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1378 0, 0, 0, 0, /* Pos, Size, ignored */
1379 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1382 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1383 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1385 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1386 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1387 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1390 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1391 HRESULT hr
= WINED3D_OK
;
1392 IUnknown
*bufferParent
;
1393 BOOL displaymode_set
= FALSE
;
1395 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1397 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1398 * does a device hold a reference to a swap chain giving them a lifetime of the device
1399 * or does the swap chain notify the device of its destruction.
1400 *******************************/
1402 /* Check the params */
1403 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1404 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1405 return WINED3DERR_INVALIDCALL
;
1406 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1407 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");
1410 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1412 /*********************
1413 * Lookup the window Handle and the relating X window handle
1414 ********************/
1416 /* Setup hwnd we are using, plus which display this equates to */
1417 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1418 if (!object
->win_handle
) {
1419 object
->win_handle
= This
->createParms
.hFocusWindow
;
1421 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, object
->win_handle
);
1423 hDc
= GetDC(object
->win_handle
);
1424 TRACE("Using hDc %p\n", hDc
);
1427 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1428 return WINED3DERR_NOTAVAILABLE
;
1431 object
->orig_width
= GetSystemMetrics(SM_CXSCREEN
);
1432 object
->orig_height
= GetSystemMetrics(SM_CYSCREEN
);
1433 object
->orig_fmt
= pixelformat_for_depth(GetDeviceCaps(hDc
, BITSPIXEL
) * GetDeviceCaps(hDc
, PLANES
));
1434 ReleaseDC(object
->win_handle
, hDc
);
1436 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1437 * then the corresponding dimension of the client area of the hDeviceWindow
1438 * (or the focus window, if hDeviceWindow is NULL) is taken.
1439 **********************/
1441 if (pPresentationParameters
->Windowed
&&
1442 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1443 (pPresentationParameters
->BackBufferHeight
== 0) ||
1444 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1447 GetClientRect(object
->win_handle
, &Rect
);
1449 if (pPresentationParameters
->BackBufferWidth
== 0) {
1450 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1451 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1453 if (pPresentationParameters
->BackBufferHeight
== 0) {
1454 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1455 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1457 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1458 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1459 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1463 /* Put the correct figures in the presentation parameters */
1464 TRACE("Copying across presentation parameters\n");
1465 object
->presentParms
= *pPresentationParameters
;
1467 TRACE("calling rendertarget CB\n");
1468 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1470 object
->presentParms
.BackBufferWidth
,
1471 object
->presentParms
.BackBufferHeight
,
1472 object
->presentParms
.BackBufferFormat
,
1473 object
->presentParms
.MultiSampleType
,
1474 object
->presentParms
.MultiSampleQuality
,
1475 TRUE
/* Lockable */,
1476 &object
->frontBuffer
,
1477 NULL
/* pShared (always null)*/);
1478 if (object
->frontBuffer
!= NULL
) {
1479 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1480 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1482 ERR("Failed to create the front buffer\n");
1486 /*********************
1487 * Windowed / Fullscreen
1488 *******************/
1491 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1492 * so we should really check to see if there is a fullscreen swapchain already
1493 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1494 **************************************/
1496 if (!pPresentationParameters
->Windowed
) {
1503 /* Get info on the current display setup */
1505 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1508 /* Change the display settings */
1509 memset(&devmode
, 0, sizeof(devmode
));
1510 devmode
.dmSize
= sizeof(devmode
);
1511 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1512 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1513 devmode
.dmPelsWidth
= pPresentationParameters
->BackBufferWidth
;
1514 devmode
.dmPelsHeight
= pPresentationParameters
->BackBufferHeight
;
1515 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1516 displaymode_set
= TRUE
;
1518 /* For GetDisplayMode */
1519 This
->ddraw_width
= devmode
.dmPelsWidth
;
1520 This
->ddraw_height
= devmode
.dmPelsHeight
;
1521 This
->ddraw_format
= pPresentationParameters
->BackBufferFormat
;
1523 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1525 /* And finally clip mouse to our screen */
1526 SetRect(&clip_rc
, 0, 0, devmode
.dmPelsWidth
, devmode
.dmPelsHeight
);
1527 ClipCursor(&clip_rc
);
1531 * Create an opengl context for the display visual
1532 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1533 * use different properties after that point in time. FIXME: How to handle when requested format
1534 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1535 * it chooses is identical to the one already being used!
1536 **********************************/
1537 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1539 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1540 if(!object
->context
)
1541 return E_OUTOFMEMORY
;
1542 object
->num_contexts
= 1;
1544 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1545 if (!object
->context
[0]) {
1546 ERR("Failed to create a new context\n");
1547 hr
= WINED3DERR_NOTAVAILABLE
;
1550 TRACE("Context created (HWND=%p, glContext=%p)\n",
1551 object
->win_handle
, object
->context
[0]->glCtx
);
1554 /*********************
1555 * Create the back, front and stencil buffers
1556 *******************/
1557 if(object
->presentParms
.BackBufferCount
> 0) {
1560 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1561 if(!object
->backBuffer
) {
1562 ERR("Out of memory\n");
1567 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1568 TRACE("calling rendertarget CB\n");
1569 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1571 object
->presentParms
.BackBufferWidth
,
1572 object
->presentParms
.BackBufferHeight
,
1573 object
->presentParms
.BackBufferFormat
,
1574 object
->presentParms
.MultiSampleType
,
1575 object
->presentParms
.MultiSampleQuality
,
1576 TRUE
/* Lockable */,
1577 &object
->backBuffer
[i
],
1578 NULL
/* pShared (always null)*/);
1579 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1580 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1582 ERR("Cannot create new back buffer\n");
1586 glDrawBuffer(GL_BACK
);
1587 checkGLcall("glDrawBuffer(GL_BACK)");
1591 object
->backBuffer
= NULL
;
1593 /* Single buffering - draw to front buffer */
1595 glDrawBuffer(GL_FRONT
);
1596 checkGLcall("glDrawBuffer(GL_FRONT)");
1600 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1601 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1602 TRACE("Creating depth stencil buffer\n");
1603 if (This
->auto_depth_stencil_buffer
== NULL
) {
1604 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1606 object
->presentParms
.BackBufferWidth
,
1607 object
->presentParms
.BackBufferHeight
,
1608 object
->presentParms
.AutoDepthStencilFormat
,
1609 object
->presentParms
.MultiSampleType
,
1610 object
->presentParms
.MultiSampleQuality
,
1611 FALSE
/* FIXME: Discard */,
1612 &This
->auto_depth_stencil_buffer
,
1613 NULL
/* pShared (always null)*/ );
1614 if (This
->auto_depth_stencil_buffer
!= NULL
)
1615 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1618 /** TODO: A check on width, height and multisample types
1619 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1620 ****************************/
1621 object
->wantsDepthStencilBuffer
= TRUE
;
1623 object
->wantsDepthStencilBuffer
= FALSE
;
1626 TRACE("Created swapchain %p\n", object
);
1627 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1631 if (displaymode_set
) {
1637 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1640 /* Get info on the current display setup */
1642 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1645 /* Change the display settings */
1646 memset(&devmode
, 0, sizeof(devmode
));
1647 devmode
.dmSize
= sizeof(devmode
);
1648 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1649 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1650 devmode
.dmPelsWidth
= object
->orig_width
;
1651 devmode
.dmPelsHeight
= object
->orig_height
;
1652 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1655 if (object
->backBuffer
) {
1657 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1658 if(object
->backBuffer
[i
]) {
1659 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1660 IUnknown_Release(bufferParent
); /* once for the get parent */
1661 if (IUnknown_Release(bufferParent
) > 0) {
1662 FIXME("(%p) Something's still holding the back buffer\n",This
);
1666 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1667 object
->backBuffer
= NULL
;
1669 if(object
->context
[0])
1670 DestroyContext(This
, object
->context
[0]);
1671 if(object
->frontBuffer
) {
1672 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1673 IUnknown_Release(bufferParent
); /* once for the get parent */
1674 if (IUnknown_Release(bufferParent
) > 0) {
1675 FIXME("(%p) Something's still holding the front buffer\n",This
);
1678 HeapFree(GetProcessHeap(), 0, object
);
1682 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1683 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1684 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1685 TRACE("(%p)\n", This
);
1687 return This
->NumberOfSwapChains
;
1690 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1691 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1692 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1694 if(iSwapChain
< This
->NumberOfSwapChains
) {
1695 *pSwapChain
= This
->swapchains
[iSwapChain
];
1696 IWineD3DSwapChain_AddRef(*pSwapChain
);
1697 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1700 TRACE("Swapchain out of range\n");
1702 return WINED3DERR_INVALIDCALL
;
1707 * Vertex Declaration
1709 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1710 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, size_t element_count
) {
1711 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1712 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1713 HRESULT hr
= WINED3D_OK
;
1715 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1716 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1718 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1720 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1725 static size_t ConvertFvfToDeclaration(DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1727 unsigned int idx
, idx2
;
1728 unsigned int offset
;
1729 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1730 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1731 BOOL has_blend_idx
= has_blend
&&
1732 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1733 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1734 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1735 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1736 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1737 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1738 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1740 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1741 DWORD texcoords
= (fvf
& 0x00FF0000) >> 16;
1743 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1744 WINED3DVERTEXELEMENT
*elements
= NULL
;
1747 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1748 if (has_blend_idx
) num_blends
--;
1750 /* Compute declaration size */
1751 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1752 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1754 /* convert the declaration */
1755 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1759 memcpy(&elements
[size
-1], &end_element
, sizeof(WINED3DVERTEXELEMENT
));
1762 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1763 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1764 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1767 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1768 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1770 elements
[idx
].UsageIndex
= 0;
1773 if (has_blend
&& (num_blends
> 0)) {
1774 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1775 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1777 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1778 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1779 elements
[idx
].UsageIndex
= 0;
1782 if (has_blend_idx
) {
1783 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1784 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1785 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1786 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1787 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1789 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1790 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1791 elements
[idx
].UsageIndex
= 0;
1795 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1796 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1797 elements
[idx
].UsageIndex
= 0;
1801 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1802 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1803 elements
[idx
].UsageIndex
= 0;
1807 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1808 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1809 elements
[idx
].UsageIndex
= 0;
1813 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1814 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1815 elements
[idx
].UsageIndex
= 1;
1818 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1819 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1820 switch (numcoords
) {
1821 case WINED3DFVF_TEXTUREFORMAT1
:
1822 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1824 case WINED3DFVF_TEXTUREFORMAT2
:
1825 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1827 case WINED3DFVF_TEXTUREFORMAT3
:
1828 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1830 case WINED3DFVF_TEXTUREFORMAT4
:
1831 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1834 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1835 elements
[idx
].UsageIndex
= idx2
;
1839 /* Now compute offsets, and initialize the rest of the fields */
1840 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1841 elements
[idx
].Stream
= 0;
1842 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1843 elements
[idx
].Offset
= offset
;
1844 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1847 *ppVertexElements
= elements
;
1851 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1852 WINED3DVERTEXELEMENT
* elements
= NULL
;
1856 size
= ConvertFvfToDeclaration(Fvf
, &elements
);
1857 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1859 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1860 HeapFree(GetProcessHeap(), 0, elements
);
1861 if (hr
!= S_OK
) return hr
;
1866 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1867 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1868 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1869 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1870 HRESULT hr
= WINED3D_OK
;
1871 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1872 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1874 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1876 if (vertex_declaration
) {
1877 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1880 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1882 if (WINED3D_OK
!= hr
) {
1883 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1884 IWineD3DVertexShader_Release(*ppVertexShader
);
1885 return WINED3DERR_INVALIDCALL
;
1891 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1892 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1893 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1894 HRESULT hr
= WINED3D_OK
;
1896 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1897 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1898 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1899 if (WINED3D_OK
== hr
) {
1900 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1902 WARN("(%p) : Failed to create pixel shader\n", This
);
1908 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1909 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1910 IWineD3DPaletteImpl
*object
;
1912 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1914 /* Create the new object */
1915 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1917 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1918 return E_OUTOFMEMORY
;
1921 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1923 object
->Flags
= Flags
;
1924 object
->parent
= Parent
;
1925 object
->wineD3DDevice
= This
;
1926 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1928 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1931 HeapFree( GetProcessHeap(), 0, object
);
1932 return E_OUTOFMEMORY
;
1935 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1937 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1941 *Palette
= (IWineD3DPalette
*) object
;
1946 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1950 HDC dcb
= NULL
, dcs
= NULL
;
1951 WINEDDCOLORKEY colorkey
;
1953 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1956 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1957 dcb
= CreateCompatibleDC(NULL
);
1959 SelectObject(dcb
, hbm
);
1963 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1964 * couldn't be loaded
1966 memset(&bm
, 0, sizeof(bm
));
1971 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1972 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1973 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1975 ERR("Wine logo requested, but failed to create surface\n");
1980 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1981 if(FAILED(hr
)) goto out
;
1982 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1983 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1985 colorkey
.dwColorSpaceLowValue
= 0;
1986 colorkey
.dwColorSpaceHighValue
= 0;
1987 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1989 /* Fill the surface with a white color to show that wined3d is there */
1990 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2003 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2004 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2005 IWineD3DSwapChainImpl
*swapchain
;
2009 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
2010 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2012 /* TODO: Test if OpenGL is compiled in and loaded */
2014 TRACE("(%p) : Creating stateblock\n", This
);
2015 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2016 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2018 (IWineD3DStateBlock
**)&This
->stateBlock
,
2020 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2021 WARN("Failed to create stateblock\n");
2024 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2025 This
->updateStateBlock
= This
->stateBlock
;
2026 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2028 hr
= allocate_shader_constants(This
->updateStateBlock
);
2029 if (WINED3D_OK
!= hr
) {
2033 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2034 This
->fbo_color_attachments
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2035 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2037 /* Initialize the texture unit mapping to a 1:1 mapping */
2038 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2039 if (state
< GL_LIMITS(fragment_samplers
)) {
2040 This
->texUnitMap
[state
] = state
;
2041 This
->rev_tex_unit_map
[state
] = state
;
2043 This
->texUnitMap
[state
] = -1;
2044 This
->rev_tex_unit_map
[state
] = -1;
2048 /* Setup the implicit swapchain */
2049 TRACE("Creating implicit swapchain\n");
2050 hr
=D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2051 if (FAILED(hr
) || !swapchain
) {
2052 WARN("Failed to create implicit swapchain\n");
2056 This
->NumberOfSwapChains
= 1;
2057 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2058 if(!This
->swapchains
) {
2059 ERR("Out of memory!\n");
2062 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2064 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2065 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2066 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2067 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2070 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2071 This
->render_targets
[0] = swapchain
->frontBuffer
;
2072 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2074 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2075 This
->activeContext
= swapchain
->context
[0];
2076 This
->lastThread
= GetCurrentThreadId();
2078 /* Depth Stencil support */
2079 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2080 if (NULL
!= This
->stencilBufferTarget
) {
2081 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2084 /* Set up some starting GL setup */
2087 /* Setup all the devices defaults */
2088 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2090 IWineD3DImpl_CheckGraphicsMemory();
2093 { /* Set a default viewport */
2097 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2098 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2101 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2104 /* Initialize the current view state */
2105 This
->view_ident
= 1;
2106 This
->contexts
[0]->last_was_rhw
= 0;
2107 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2108 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2110 switch(wined3d_settings
.offscreen_rendering_mode
) {
2113 This
->offscreenBuffer
= GL_BACK
;
2116 case ORM_BACKBUFFER
:
2118 if(GL_LIMITS(aux_buffers
) > 0) {
2119 TRACE("Using auxilliary buffer for offscreen rendering\n");
2120 This
->offscreenBuffer
= GL_AUX0
;
2122 TRACE("Using back buffer for offscreen rendering\n");
2123 This
->offscreenBuffer
= GL_BACK
;
2128 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2131 /* Clear the screen */
2132 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2133 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2136 This
->d3d_initialized
= TRUE
;
2138 if(wined3d_settings
.logo
) {
2139 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2144 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2145 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2146 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2147 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2148 This
->NumberOfSwapChains
= 0;
2150 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2152 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2153 if(This
->stateBlock
) {
2154 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2155 This
->stateBlock
= NULL
;
2160 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2161 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2164 TRACE("(%p)\n", This
);
2166 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2168 /* I don't think that the interface guarants that the device is destroyed from the same thread
2169 * it was created. Thus make sure a context is active for the glDelete* calls
2171 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2173 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2175 TRACE("Deleting high order patches\n");
2176 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2177 struct list
*e1
, *e2
;
2178 struct WineD3DRectPatch
*patch
;
2179 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2180 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2181 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2185 /* Delete the palette conversion shader if it is around */
2186 if(This
->paletteConversionShader
) {
2187 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2188 This
->paletteConversionShader
= 0;
2191 /* Delete the pbuffer context if there is any */
2192 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2194 /* Delete the mouse cursor texture */
2195 if(This
->cursorTexture
) {
2197 glDeleteTextures(1, &This
->cursorTexture
);
2199 This
->cursorTexture
= 0;
2202 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2203 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2205 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2206 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2209 /* Release the update stateblock */
2210 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2211 if(This
->updateStateBlock
!= This
->stateBlock
)
2212 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2214 This
->updateStateBlock
= NULL
;
2216 { /* because were not doing proper internal refcounts releasing the primary state block
2217 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2218 to set this->stateBlock = NULL; first */
2219 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2220 This
->stateBlock
= NULL
;
2222 /* Release the stateblock */
2223 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2224 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2228 /* Release the buffers (with sanity checks)*/
2229 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2230 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2231 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2232 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2234 This
->stencilBufferTarget
= NULL
;
2236 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2237 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2238 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2240 TRACE("Setting rendertarget to NULL\n");
2241 This
->render_targets
[0] = NULL
;
2243 if (This
->auto_depth_stencil_buffer
) {
2244 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2245 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2247 This
->auto_depth_stencil_buffer
= NULL
;
2250 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2251 TRACE("Releasing the implicit swapchain %d\n", i
);
2252 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2253 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2257 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2258 This
->swapchains
= NULL
;
2259 This
->NumberOfSwapChains
= 0;
2261 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2262 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2263 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2264 This
->render_targets
= NULL
;
2265 This
->fbo_color_attachments
= NULL
;
2266 This
->draw_buffers
= NULL
;
2269 This
->d3d_initialized
= FALSE
;
2273 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2274 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2275 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2277 /* Setup the window for fullscreen mode */
2278 if(fullscreen
&& !This
->ddraw_fullscreen
) {
2279 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
2280 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
2281 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
2284 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2285 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2286 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2289 This
->ddraw_fullscreen
= fullscreen
;
2292 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2293 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2294 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2296 * There is no way to deactivate thread safety once it is enabled.
2298 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2299 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2301 /*For now just store the flag(needed in case of ddraw) */
2302 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2307 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2309 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2311 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2314 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2316 /* Resize the screen even without a window:
2317 * The app could have unset it with SetCooperativeLevel, but not called
2318 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2319 * but we don't have any hwnd
2322 memset(&devmode
, 0, sizeof(devmode
));
2323 devmode
.dmSize
= sizeof(devmode
);
2324 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2325 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2326 if(devmode
.dmBitsPerPel
== 24) devmode
.dmBitsPerPel
= 32;
2327 devmode
.dmPelsWidth
= pMode
->Width
;
2328 devmode
.dmPelsHeight
= pMode
->Height
;
2330 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2331 if (pMode
->RefreshRate
!= 0) {
2332 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2335 /* Only change the mode if necessary */
2336 if( (This
->ddraw_width
== pMode
->Width
) &&
2337 (This
->ddraw_height
== pMode
->Height
) &&
2338 (This
->ddraw_format
== pMode
->Format
) &&
2339 (pMode
->RefreshRate
== 0) ) {
2343 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2344 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2345 if(devmode
.dmDisplayFrequency
!= 0) {
2346 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2347 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2348 devmode
.dmDisplayFrequency
= 0;
2349 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2351 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2352 return WINED3DERR_NOTAVAILABLE
;
2356 /* Store the new values */
2357 This
->ddraw_width
= pMode
->Width
;
2358 This
->ddraw_height
= pMode
->Height
;
2359 This
->ddraw_format
= pMode
->Format
;
2361 /* Only do this with a window of course */
2362 if(This
->ddraw_window
)
2363 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2365 /* And finally clip mouse to our screen */
2366 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2367 ClipCursor(&clip_rc
);
2372 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2373 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2374 *ppD3D
= This
->wineD3D
;
2375 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2376 IWineD3D_AddRef(*ppD3D
);
2380 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2381 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2383 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2384 (This
->adapter
->TextureRam
/(1024*1024)),
2385 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2386 /* return simulated texture memory left */
2387 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2395 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2396 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2398 /* Update the current state block */
2399 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2401 if(This
->updateStateBlock
->fvf
== fvf
) {
2402 TRACE("Application is setting the old fvf over, nothing to do\n");
2406 This
->updateStateBlock
->fvf
= fvf
;
2407 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2408 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2413 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2414 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2415 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2416 *pfvf
= This
->stateBlock
->fvf
;
2421 * Get / Set Stream Source
2423 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2424 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2425 IWineD3DVertexBuffer
*oldSrc
;
2427 if (StreamNumber
>= MAX_STREAMS
) {
2428 WARN("Stream out of range %d\n", StreamNumber
);
2429 return WINED3DERR_INVALIDCALL
;
2432 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2433 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2435 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2437 if(oldSrc
== pStreamData
&&
2438 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2439 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2440 TRACE("Application is setting the old values over, nothing to do\n");
2444 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2446 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2447 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2450 /* Handle recording of state blocks */
2451 if (This
->isRecordingState
) {
2452 TRACE("Recording... not performing anything\n");
2453 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2454 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2458 /* Need to do a getParent and pass the reffs up */
2459 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2460 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2461 so for now, just count internally */
2462 if (pStreamData
!= NULL
) {
2463 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2464 InterlockedIncrement(&vbImpl
->bindCount
);
2465 IWineD3DVertexBuffer_AddRef(pStreamData
);
2467 if (oldSrc
!= NULL
) {
2468 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2469 IWineD3DVertexBuffer_Release(oldSrc
);
2472 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2477 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2478 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2480 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2481 This
->stateBlock
->streamSource
[StreamNumber
],
2482 This
->stateBlock
->streamOffset
[StreamNumber
],
2483 This
->stateBlock
->streamStride
[StreamNumber
]);
2485 if (StreamNumber
>= MAX_STREAMS
) {
2486 WARN("Stream out of range %d\n", StreamNumber
);
2487 return WINED3DERR_INVALIDCALL
;
2489 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2490 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2492 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2495 if (*pStream
!= NULL
) {
2496 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2501 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2502 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2503 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2504 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2506 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2507 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2509 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2510 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2512 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2513 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2514 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2520 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2521 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2523 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2524 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2526 TRACE("(%p) : returning %d\n", This
, *Divider
);
2532 * Get / Set & Multiply Transform
2534 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2535 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2537 /* Most of this routine, comments included copied from ddraw tree initially: */
2538 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2540 /* Handle recording of state blocks */
2541 if (This
->isRecordingState
) {
2542 TRACE("Recording... not performing anything\n");
2543 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2544 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2549 * If the new matrix is the same as the current one,
2550 * we cut off any further processing. this seems to be a reasonable
2551 * optimization because as was noticed, some apps (warcraft3 for example)
2552 * tend towards setting the same matrix repeatedly for some reason.
2554 * From here on we assume that the new matrix is different, wherever it matters.
2556 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2557 TRACE("The app is setting the same matrix over again\n");
2560 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2564 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2565 where ViewMat = Camera space, WorldMat = world space.
2567 In OpenGL, camera and world space is combined into GL_MODELVIEW
2568 matrix. The Projection matrix stay projection matrix.
2571 /* Capture the times we can just ignore the change for now */
2572 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2573 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2574 /* Handled by the state manager */
2577 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2581 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2583 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2584 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2588 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2589 WINED3DMATRIX
*mat
= NULL
;
2592 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2593 * below means it will be recorded in a state block change, but it
2594 * works regardless where it is recorded.
2595 * If this is found to be wrong, change to StateBlock.
2597 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2598 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2600 if (State
< HIGHEST_TRANSFORMSTATE
)
2602 mat
= &This
->updateStateBlock
->transforms
[State
];
2604 FIXME("Unhandled transform state!!\n");
2607 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2609 /* Apply change via set transform - will reapply to eg. lights this way */
2610 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2616 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2617 you can reference any indexes you want as long as that number max are enabled at any
2618 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2619 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2620 but when recording, just build a chain pretty much of commands to be replayed. */
2622 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2624 PLIGHTINFOEL
*object
= NULL
;
2625 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2628 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2629 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2631 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2635 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2636 return WINED3DERR_INVALIDCALL
;
2639 switch(pLight
->Type
) {
2640 case WINED3DLIGHT_POINT
:
2641 case WINED3DLIGHT_SPOT
:
2642 case WINED3DLIGHT_PARALLELPOINT
:
2643 case WINED3DLIGHT_GLSPOT
:
2644 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2647 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2648 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2649 return WINED3DERR_INVALIDCALL
;
2653 case WINED3DLIGHT_DIRECTIONAL
:
2654 /* Ignores attenuation */
2658 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL
;
2662 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2663 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2664 if(object
->OriginalIndex
== Index
) break;
2669 TRACE("Adding new light\n");
2670 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2672 ERR("Out of memory error when allocating a light\n");
2673 return E_OUTOFMEMORY
;
2675 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2676 object
->glIndex
= -1;
2677 object
->OriginalIndex
= Index
;
2678 object
->changed
= TRUE
;
2681 /* Initialize the object */
2682 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
,
2683 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2684 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2685 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2686 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2687 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2688 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2690 /* Save away the information */
2691 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2693 switch (pLight
->Type
) {
2694 case WINED3DLIGHT_POINT
:
2696 object
->lightPosn
[0] = pLight
->Position
.x
;
2697 object
->lightPosn
[1] = pLight
->Position
.y
;
2698 object
->lightPosn
[2] = pLight
->Position
.z
;
2699 object
->lightPosn
[3] = 1.0f
;
2700 object
->cutoff
= 180.0f
;
2704 case WINED3DLIGHT_DIRECTIONAL
:
2706 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2707 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2708 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2709 object
->lightPosn
[3] = 0.0;
2710 object
->exponent
= 0.0f
;
2711 object
->cutoff
= 180.0f
;
2714 case WINED3DLIGHT_SPOT
:
2716 object
->lightPosn
[0] = pLight
->Position
.x
;
2717 object
->lightPosn
[1] = pLight
->Position
.y
;
2718 object
->lightPosn
[2] = pLight
->Position
.z
;
2719 object
->lightPosn
[3] = 1.0;
2722 object
->lightDirn
[0] = pLight
->Direction
.x
;
2723 object
->lightDirn
[1] = pLight
->Direction
.y
;
2724 object
->lightDirn
[2] = pLight
->Direction
.z
;
2725 object
->lightDirn
[3] = 1.0;
2728 * opengl-ish and d3d-ish spot lights use too different models for the
2729 * light "intensity" as a function of the angle towards the main light direction,
2730 * so we only can approximate very roughly.
2731 * however spot lights are rather rarely used in games (if ever used at all).
2732 * furthermore if still used, probably nobody pays attention to such details.
2734 if (pLight
->Falloff
== 0) {
2735 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2736 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2737 * will always be 1.0 for both of them, and we don't have to care for the
2738 * rest of the rather complex calculation
2740 object
->exponent
= 0;
2742 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2743 if (rho
< 0.0001) rho
= 0.0001f
;
2744 object
->exponent
= -0.3/log(cos(rho
/2));
2746 if (object
->exponent
> 128.0) {
2747 object
->exponent
= 128.0;
2749 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2755 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2758 /* Update the live definitions if the light is currently assigned a glIndex */
2759 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2760 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2765 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2766 PLIGHTINFOEL
*lightInfo
= NULL
;
2767 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2768 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2770 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2772 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2773 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2774 if(lightInfo
->OriginalIndex
== Index
) break;
2778 if (lightInfo
== NULL
) {
2779 TRACE("Light information requested but light not defined\n");
2780 return WINED3DERR_INVALIDCALL
;
2783 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2788 * Get / Set Light Enable
2789 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2791 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2792 PLIGHTINFOEL
*lightInfo
= NULL
;
2793 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2794 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2796 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2798 /* Tests show true = 128...not clear why */
2799 Enable
= Enable
? 128: 0;
2801 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2802 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2803 if(lightInfo
->OriginalIndex
== Index
) break;
2806 TRACE("Found light: %p\n", lightInfo
);
2808 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2809 if (lightInfo
== NULL
) {
2811 TRACE("Light enabled requested but light not defined, so defining one!\n");
2812 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2814 /* Search for it again! Should be fairly quick as near head of list */
2815 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2816 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2817 if(lightInfo
->OriginalIndex
== Index
) break;
2820 if (lightInfo
== NULL
) {
2821 FIXME("Adding default lights has failed dismally\n");
2822 return WINED3DERR_INVALIDCALL
;
2826 lightInfo
->enabledChanged
= TRUE
;
2828 if(lightInfo
->glIndex
!= -1) {
2829 if(!This
->isRecordingState
) {
2830 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2833 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2834 lightInfo
->glIndex
= -1;
2836 TRACE("Light already disabled, nothing to do\n");
2839 if (lightInfo
->glIndex
!= -1) {
2841 TRACE("Nothing to do as light was enabled\n");
2844 /* Find a free gl light */
2845 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2846 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2847 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2848 lightInfo
->glIndex
= i
;
2852 if(lightInfo
->glIndex
== -1) {
2853 ERR("Too many concurrently active lights\n");
2854 return WINED3DERR_INVALIDCALL
;
2857 /* i == lightInfo->glIndex */
2858 if(!This
->isRecordingState
) {
2859 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2867 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2869 PLIGHTINFOEL
*lightInfo
= NULL
;
2870 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2872 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2873 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2875 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2876 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2877 if(lightInfo
->OriginalIndex
== Index
) break;
2881 if (lightInfo
== NULL
) {
2882 TRACE("Light enabled state requested but light not defined\n");
2883 return WINED3DERR_INVALIDCALL
;
2885 /* true is 128 according to SetLightEnable */
2886 *pEnable
= lightInfo
->glIndex
!= -1 ? 128 : 0;
2891 * Get / Set Clip Planes
2893 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2894 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2895 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2897 /* Validate Index */
2898 if (Index
>= GL_LIMITS(clipplanes
)) {
2899 TRACE("Application has requested clipplane this device doesn't support\n");
2900 return WINED3DERR_INVALIDCALL
;
2903 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2905 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2906 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2907 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2908 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2909 TRACE("Application is setting old values over, nothing to do\n");
2913 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2914 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2915 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2916 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2918 /* Handle recording of state blocks */
2919 if (This
->isRecordingState
) {
2920 TRACE("Recording... not performing anything\n");
2924 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2929 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2930 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2931 TRACE("(%p) : for idx %d\n", This
, Index
);
2933 /* Validate Index */
2934 if (Index
>= GL_LIMITS(clipplanes
)) {
2935 TRACE("Application has requested clipplane this device doesn't support\n");
2936 return WINED3DERR_INVALIDCALL
;
2939 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2940 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2941 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2942 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2947 * Get / Set Clip Plane Status
2948 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2950 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2951 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2952 FIXME("(%p) : stub\n", This
);
2953 if (NULL
== pClipStatus
) {
2954 return WINED3DERR_INVALIDCALL
;
2956 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2957 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2961 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2962 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2963 FIXME("(%p) : stub\n", This
);
2964 if (NULL
== pClipStatus
) {
2965 return WINED3DERR_INVALIDCALL
;
2967 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2968 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2973 * Get / Set Material
2975 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2976 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2978 This
->updateStateBlock
->changed
.material
= TRUE
;
2979 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2981 /* Handle recording of state blocks */
2982 if (This
->isRecordingState
) {
2983 TRACE("Recording... not performing anything\n");
2987 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2991 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2992 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2993 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
2994 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2995 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2996 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2997 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2998 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2999 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3000 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3001 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3002 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3010 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3011 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3012 IWineD3DIndexBuffer
*oldIdxs
;
3014 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3015 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3017 This
->updateStateBlock
->changed
.indices
= TRUE
;
3018 This
->updateStateBlock
->pIndexData
= pIndexData
;
3020 /* Handle recording of state blocks */
3021 if (This
->isRecordingState
) {
3022 TRACE("Recording... not performing anything\n");
3023 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3024 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3028 if(oldIdxs
!= pIndexData
) {
3029 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3030 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3031 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3036 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3037 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3039 *ppIndexData
= This
->stateBlock
->pIndexData
;
3041 /* up ref count on ppindexdata */
3043 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3044 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3046 TRACE("(%p) No index data set\n", This
);
3048 TRACE("Returning %p\n", *ppIndexData
);
3053 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3054 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3055 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3056 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3058 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3059 TRACE("Application is setting the old value over, nothing to do\n");
3063 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3065 if (This
->isRecordingState
) {
3066 TRACE("Recording... not performing anything\n");
3069 /* The base vertex index affects the stream sources */
3070 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3074 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3075 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3076 TRACE("(%p) : base_index %p\n", This
, base_index
);
3078 *base_index
= This
->stateBlock
->baseVertexIndex
;
3080 TRACE("Returning %u\n", *base_index
);
3086 * Get / Set Viewports
3088 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3089 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3091 TRACE("(%p)\n", This
);
3092 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3093 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
3095 /* Handle recording of state blocks */
3096 if (This
->isRecordingState
) {
3097 TRACE("Recording... not performing anything\n");
3101 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3102 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3104 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3109 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3110 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3111 TRACE("(%p)\n", This
);
3112 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
3117 * Get / Set Render States
3118 * TODO: Verify against dx9 definitions
3120 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3122 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3123 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3125 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3127 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3128 This
->updateStateBlock
->renderState
[State
] = Value
;
3130 /* Handle recording of state blocks */
3131 if (This
->isRecordingState
) {
3132 TRACE("Recording... not performing anything\n");
3136 /* Compared here and not before the assignment to allow proper stateblock recording */
3137 if(Value
== oldValue
) {
3138 TRACE("Application is setting the old value over, nothing to do\n");
3140 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3146 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3147 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3148 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3149 *pValue
= This
->stateBlock
->renderState
[State
];
3154 * Get / Set Sampler States
3155 * TODO: Verify against dx9 definitions
3158 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3159 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3162 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3163 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3165 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3166 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3170 * SetSampler is designed to allow for more than the standard up to 8 textures
3171 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3172 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3174 * http://developer.nvidia.com/object/General_FAQ.html#t6
3176 * There are two new settings for GForce
3178 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3179 * and the texture one:
3180 * GL_MAX_TEXTURE_COORDS_ARB.
3181 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3184 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3185 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3186 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3188 /* Handle recording of state blocks */
3189 if (This
->isRecordingState
) {
3190 TRACE("Recording... not performing anything\n");
3194 if(oldValue
== Value
) {
3195 TRACE("Application is setting the old value over, nothing to do\n");
3199 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3204 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3205 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3207 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3208 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3210 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3211 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3214 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3215 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3220 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3221 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3223 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3224 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3225 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3228 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3230 if(This
->isRecordingState
) {
3231 TRACE("Recording... not performing anything\n");
3235 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3240 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3241 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3243 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
3244 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3248 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3249 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3250 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3252 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3254 This
->updateStateBlock
->vertexDecl
= pDecl
;
3255 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3257 if (This
->isRecordingState
) {
3258 TRACE("Recording... not performing anything\n");
3260 } else if(pDecl
== oldDecl
) {
3261 /* Checked after the assignment to allow proper stateblock recording */
3262 TRACE("Application is setting the old declaration over, nothing to do\n");
3266 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3270 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3271 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3273 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3275 *ppDecl
= This
->stateBlock
->vertexDecl
;
3276 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3280 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3281 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3282 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3284 This
->updateStateBlock
->vertexShader
= pShader
;
3285 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3287 if (This
->isRecordingState
) {
3288 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3289 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3290 TRACE("Recording... not performing anything\n");
3292 } else if(oldShader
== pShader
) {
3293 /* Checked here to allow proper stateblock recording */
3294 TRACE("App is setting the old shader over, nothing to do\n");
3298 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3299 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3300 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3302 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3307 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3308 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3310 if (NULL
== ppShader
) {
3311 return WINED3DERR_INVALIDCALL
;
3313 *ppShader
= This
->stateBlock
->vertexShader
;
3314 if( NULL
!= *ppShader
)
3315 IWineD3DVertexShader_AddRef(*ppShader
);
3317 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3321 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3322 IWineD3DDevice
*iface
,
3324 CONST BOOL
*srcData
,
3327 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3328 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3330 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3331 iface
, srcData
, start
, count
);
3333 if (srcData
== NULL
|| cnt
< 0)
3334 return WINED3DERR_INVALIDCALL
;
3336 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3337 for (i
= 0; i
< cnt
; i
++)
3338 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3340 for (i
= start
; i
< cnt
+ start
; ++i
) {
3341 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3344 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3349 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3350 IWineD3DDevice
*iface
,
3355 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3356 int cnt
= min(count
, MAX_CONST_B
- start
);
3358 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3359 iface
, dstData
, start
, count
);
3361 if (dstData
== NULL
|| cnt
< 0)
3362 return WINED3DERR_INVALIDCALL
;
3364 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3368 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3369 IWineD3DDevice
*iface
,
3374 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3375 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3377 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3378 iface
, srcData
, start
, count
);
3380 if (srcData
== NULL
|| cnt
< 0)
3381 return WINED3DERR_INVALIDCALL
;
3383 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3384 for (i
= 0; i
< cnt
; i
++)
3385 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3386 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3388 for (i
= start
; i
< cnt
+ start
; ++i
) {
3389 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3392 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3397 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3398 IWineD3DDevice
*iface
,
3403 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3404 int cnt
= min(count
, MAX_CONST_I
- start
);
3406 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3407 iface
, dstData
, start
, count
);
3409 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3410 return WINED3DERR_INVALIDCALL
;
3412 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3416 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3417 IWineD3DDevice
*iface
,
3419 CONST
float *srcData
,
3422 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3425 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3426 iface
, srcData
, start
, count
);
3428 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3429 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3430 return WINED3DERR_INVALIDCALL
;
3432 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3434 for (i
= 0; i
< count
; i
++)
3435 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3436 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3439 for (i
= start
; i
< count
+ start
; ++i
) {
3440 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3441 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3442 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3443 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3444 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3446 ptr
->idx
[ptr
->count
++] = i
;
3447 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3451 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3456 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3457 IWineD3DDevice
*iface
,
3462 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3463 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3465 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3466 iface
, dstData
, start
, count
);
3468 if (dstData
== NULL
|| cnt
< 0)
3469 return WINED3DERR_INVALIDCALL
;
3471 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3475 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3477 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3478 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3482 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3483 int i
= This
->rev_tex_unit_map
[unit
];
3484 int j
= This
->texUnitMap
[stage
];
3486 This
->texUnitMap
[stage
] = unit
;
3487 if (i
!= -1 && i
!= stage
) {
3488 This
->texUnitMap
[i
] = -1;
3491 This
->rev_tex_unit_map
[unit
] = stage
;
3492 if (j
!= -1 && j
!= unit
) {
3493 This
->rev_tex_unit_map
[j
] = -1;
3497 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3500 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3501 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3502 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3503 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3504 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3505 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3506 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3507 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3508 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3510 if (color_op
== WINED3DTOP_DISABLE
) {
3511 /* Not used, and disable higher stages */
3512 while (i
< MAX_TEXTURES
) {
3513 This
->fixed_function_usage_map
[i
] = FALSE
;
3519 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3520 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3521 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3522 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3523 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3524 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3525 This
->fixed_function_usage_map
[i
] = TRUE
;
3527 This
->fixed_function_usage_map
[i
] = FALSE
;
3530 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3531 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3536 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3539 device_update_fixed_function_usage_map(This
);
3541 if (!GL_SUPPORT(NV_REGISTER_COMBINERS
) || This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3542 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3543 if (!This
->fixed_function_usage_map
[i
]) continue;
3545 if (This
->texUnitMap
[i
] != i
) {
3546 device_map_stage(This
, i
, i
);
3547 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3548 markTextureStagesDirty(This
, i
);
3554 /* Now work out the mapping */
3556 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3557 if (!This
->fixed_function_usage_map
[i
]) continue;
3559 if (This
->texUnitMap
[i
] != tex
) {
3560 device_map_stage(This
, i
, tex
);
3561 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3562 markTextureStagesDirty(This
, i
);
3569 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3570 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3573 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3574 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3575 device_map_stage(This
, i
, i
);
3576 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3577 if (i
< MAX_TEXTURES
) {
3578 markTextureStagesDirty(This
, i
);
3584 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3585 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3587 if (current_mapping
== -1) {
3588 /* Not currently used */
3592 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3593 /* Used by a fragment sampler */
3595 if (!pshader_sampler_tokens
) {
3596 /* No pixel shader, check fixed function */
3597 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3600 /* Pixel shader, check the shader's sampler map */
3601 return !pshader_sampler_tokens
[current_mapping
];
3604 /* Used by a vertex sampler */
3605 return !vshader_sampler_tokens
[current_mapping
];
3608 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3609 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3610 DWORD
*pshader_sampler_tokens
= NULL
;
3611 int start
= GL_LIMITS(combined_samplers
) - 1;
3615 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3617 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3618 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3619 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3622 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3623 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3624 if (vshader_sampler_tokens
[i
]) {
3625 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3626 /* Already mapped somewhere */
3630 while (start
>= 0) {
3631 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3632 device_map_stage(This
, vsampler_idx
, start
);
3633 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3645 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3646 BOOL vs
= use_vs(This
);
3647 BOOL ps
= use_ps(This
);
3650 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3651 * that would be really messy and require shader recompilation
3652 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3653 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3656 device_map_psamplers(This
);
3658 device_map_fixed_function_samplers(This
);
3662 device_map_vsamplers(This
, ps
);
3666 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3667 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3668 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3669 This
->updateStateBlock
->pixelShader
= pShader
;
3670 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3672 /* Handle recording of state blocks */
3673 if (This
->isRecordingState
) {
3674 TRACE("Recording... not performing anything\n");
3677 if (This
->isRecordingState
) {
3678 TRACE("Recording... not performing anything\n");
3679 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3680 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3684 if(pShader
== oldShader
) {
3685 TRACE("App is setting the old pixel shader over, nothing to do\n");
3689 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3690 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3692 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3693 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3698 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3699 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3701 if (NULL
== ppShader
) {
3702 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3703 return WINED3DERR_INVALIDCALL
;
3706 *ppShader
= This
->stateBlock
->pixelShader
;
3707 if (NULL
!= *ppShader
) {
3708 IWineD3DPixelShader_AddRef(*ppShader
);
3710 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3714 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3715 IWineD3DDevice
*iface
,
3717 CONST BOOL
*srcData
,
3720 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3721 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3723 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3724 iface
, srcData
, start
, count
);
3726 if (srcData
== NULL
|| cnt
< 0)
3727 return WINED3DERR_INVALIDCALL
;
3729 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3730 for (i
= 0; i
< cnt
; i
++)
3731 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3733 for (i
= start
; i
< cnt
+ start
; ++i
) {
3734 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3737 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3742 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3743 IWineD3DDevice
*iface
,
3748 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3749 int cnt
= min(count
, MAX_CONST_B
- start
);
3751 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3752 iface
, dstData
, start
, count
);
3754 if (dstData
== NULL
|| cnt
< 0)
3755 return WINED3DERR_INVALIDCALL
;
3757 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3761 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3762 IWineD3DDevice
*iface
,
3767 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3768 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3770 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3771 iface
, srcData
, start
, count
);
3773 if (srcData
== NULL
|| cnt
< 0)
3774 return WINED3DERR_INVALIDCALL
;
3776 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3777 for (i
= 0; i
< cnt
; i
++)
3778 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3779 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3781 for (i
= start
; i
< cnt
+ start
; ++i
) {
3782 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3785 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3790 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3791 IWineD3DDevice
*iface
,
3796 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3797 int cnt
= min(count
, MAX_CONST_I
- start
);
3799 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3800 iface
, dstData
, start
, count
);
3802 if (dstData
== NULL
|| cnt
< 0)
3803 return WINED3DERR_INVALIDCALL
;
3805 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3809 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3810 IWineD3DDevice
*iface
,
3812 CONST
float *srcData
,
3815 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3818 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3819 iface
, srcData
, start
, count
);
3821 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3822 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3823 return WINED3DERR_INVALIDCALL
;
3825 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3827 for (i
= 0; i
< count
; i
++)
3828 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3829 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3832 for (i
= start
; i
< count
+ start
; ++i
) {
3833 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
3834 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
3835 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3836 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3837 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3839 ptr
->idx
[ptr
->count
++] = i
;
3840 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3844 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3849 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3850 IWineD3DDevice
*iface
,
3855 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3856 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3858 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3859 iface
, dstData
, start
, count
);
3861 if (dstData
== NULL
|| cnt
< 0)
3862 return WINED3DERR_INVALIDCALL
;
3864 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3868 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3870 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3871 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3873 DWORD DestFVF
= dest
->fvf
;
3875 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3879 if (lpStrideData
->u
.s
.normal
.lpData
) {
3880 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3883 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
3884 ERR("Source has no position mask\n");
3885 return WINED3DERR_INVALIDCALL
;
3888 /* We might access VBOs from this code, so hold the lock */
3891 if (dest
->resource
.allocatedMemory
== NULL
) {
3892 /* This may happen if we do direct locking into a vbo. Unlikely,
3893 * but theoretically possible(ddraw processvertices test)
3895 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3896 if(!dest
->resource
.allocatedMemory
) {
3898 ERR("Out of memory\n");
3899 return E_OUTOFMEMORY
;
3903 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3904 checkGLcall("glBindBufferARB");
3905 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3907 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3909 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3910 checkGLcall("glUnmapBufferARB");
3914 /* Get a pointer into the destination vbo(create one if none exists) and
3915 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3917 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3922 unsigned char extrabytes
= 0;
3923 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3924 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3925 * this may write 4 extra bytes beyond the area that should be written
3927 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3928 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3929 if(!dest_conv_addr
) {
3930 ERR("Out of memory\n");
3931 /* Continue without storing converted vertices */
3933 dest_conv
= dest_conv_addr
;
3937 * a) WINED3DRS_CLIPPING is enabled
3938 * b) WINED3DVOP_CLIP is passed
3940 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3941 static BOOL warned
= FALSE
;
3943 * The clipping code is not quite correct. Some things need
3944 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3945 * so disable clipping for now.
3946 * (The graphics in Half-Life are broken, and my processvertices
3947 * test crashes with IDirect3DDevice3)
3953 FIXME("Clipping is broken and disabled for now\n");
3955 } else doClip
= FALSE
;
3956 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3958 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3961 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3962 WINED3DTS_PROJECTION
,
3964 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3965 WINED3DTS_WORLDMATRIX(0),
3968 TRACE("View mat:\n");
3969 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
);
3970 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
);
3971 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
);
3972 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
);
3974 TRACE("Proj mat:\n");
3975 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
);
3976 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
);
3977 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
);
3978 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
);
3980 TRACE("World mat:\n");
3981 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
);
3982 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
);
3983 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
);
3984 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
);
3986 /* Get the viewport */
3987 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3988 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3989 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3991 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3992 multiply_matrix(&mat
,&proj_mat
,&mat
);
3994 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3996 for (i
= 0; i
< dwCount
; i
+= 1) {
3997 unsigned int tex_index
;
3999 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4000 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4001 /* The position first */
4003 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4005 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4007 /* Multiplication with world, view and projection matrix */
4008 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
);
4009 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
);
4010 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
);
4011 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
);
4013 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4015 /* WARNING: The following things are taken from d3d7 and were not yet checked
4016 * against d3d8 or d3d9!
4019 /* Clipping conditions: From
4020 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4022 * A vertex is clipped if it does not match the following requirements
4026 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4028 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4029 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4034 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4035 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4038 /* "Normal" viewport transformation (not clipped)
4039 * 1) The values are divided by rhw
4040 * 2) The y axis is negative, so multiply it with -1
4041 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4042 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4043 * 4) Multiply x with Width/2 and add Width/2
4044 * 5) The same for the height
4045 * 6) Add the viewpoint X and Y to the 2D coordinates and
4046 * The minimum Z value to z
4047 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4049 * Well, basically it's simply a linear transformation into viewport
4061 z
*= vp
.MaxZ
- vp
.MinZ
;
4063 x
+= vp
.Width
/ 2 + vp
.X
;
4064 y
+= vp
.Height
/ 2 + vp
.Y
;
4069 /* That vertex got clipped
4070 * Contrary to OpenGL it is not dropped completely, it just
4071 * undergoes a different calculation.
4073 TRACE("Vertex got clipped\n");
4080 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4081 * outside of the main vertex buffer memory. That needs some more
4086 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4089 ( (float *) dest_ptr
)[0] = x
;
4090 ( (float *) dest_ptr
)[1] = y
;
4091 ( (float *) dest_ptr
)[2] = z
;
4092 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4094 dest_ptr
+= 3 * sizeof(float);
4096 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4097 dest_ptr
+= sizeof(float);
4102 ( (float *) dest_conv
)[0] = x
* w
;
4103 ( (float *) dest_conv
)[1] = y
* w
;
4104 ( (float *) dest_conv
)[2] = z
* w
;
4105 ( (float *) dest_conv
)[3] = w
;
4107 dest_conv
+= 3 * sizeof(float);
4109 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4110 dest_conv
+= sizeof(float);
4114 if (DestFVF
& WINED3DFVF_PSIZE
) {
4115 dest_ptr
+= sizeof(DWORD
);
4116 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4118 if (DestFVF
& WINED3DFVF_NORMAL
) {
4120 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4121 /* AFAIK this should go into the lighting information */
4122 FIXME("Didn't expect the destination to have a normal\n");
4123 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4125 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4129 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4131 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4133 static BOOL warned
= FALSE
;
4136 ERR("No diffuse color in source, but destination has one\n");
4140 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4141 dest_ptr
+= sizeof(DWORD
);
4144 *( (DWORD
*) dest_conv
) = 0xffffffff;
4145 dest_conv
+= sizeof(DWORD
);
4149 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4151 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4152 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4153 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4154 dest_conv
+= sizeof(DWORD
);
4159 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4160 /* What's the color value in the feedback buffer? */
4162 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4164 static BOOL warned
= FALSE
;
4167 ERR("No specular color in source, but destination has one\n");
4171 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4172 dest_ptr
+= sizeof(DWORD
);
4175 *( (DWORD
*) dest_conv
) = 0xFF000000;
4176 dest_conv
+= sizeof(DWORD
);
4180 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4182 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4183 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4184 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4185 dest_conv
+= sizeof(DWORD
);
4190 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4192 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4193 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4195 ERR("No source texture, but destination requests one\n");
4196 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4197 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4200 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4202 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4209 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4210 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4211 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4212 dwCount
* get_flexible_vertex_size(DestFVF
),
4214 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4215 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4222 #undef copy_and_next
4224 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4225 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4226 WineDirect3DVertexStridedData strided
;
4227 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4228 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4231 ERR("Output vertex declaration not implemented yet\n");
4234 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4235 * and this call is quite performance critical, so don't call needlessly
4237 if(This
->createParms
.BehaviorFlags
& WINED3DCREATE_MULTITHREADED
) {
4238 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4241 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4242 * control the streamIsUP flag, thus restore it afterwards.
4244 This
->stateBlock
->streamIsUP
= FALSE
;
4245 memset(&strided
, 0, sizeof(strided
));
4246 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4247 This
->stateBlock
->streamIsUP
= streamWasUP
;
4249 if(vbo
|| SrcStartIndex
) {
4251 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4252 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4254 * Also get the start index in, but only loop over all elements if there's something to add at all.
4256 #define FIXSRC(type) \
4257 if(strided.u.s.type.VBO) { \
4258 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4259 strided.u.s.type.VBO = 0; \
4260 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4262 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4266 if(strided.u.s.type.lpData) { \
4267 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4270 FIXSRC(blendWeights
);
4271 FIXSRC(blendMatrixIndices
);
4276 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4277 FIXSRC(texCoords
[i
]);
4290 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4294 * Get / Set Texture Stage States
4295 * TODO: Verify against dx9 definitions
4297 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4298 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4299 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4301 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4303 if (Stage
>= MAX_TEXTURES
) {
4304 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4308 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4309 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4311 if (This
->isRecordingState
) {
4312 TRACE("Recording... not performing anything\n");
4316 /* Checked after the assignments to allow proper stateblock recording */
4317 if(oldValue
== Value
) {
4318 TRACE("App is setting the old value over, nothing to do\n");
4322 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4323 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4324 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4325 * Changes in other states are important on disabled stages too
4330 if(Type
== WINED3DTSS_COLOROP
) {
4333 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4334 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4335 * they have to be disabled
4337 * The current stage is dirtified below.
4339 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4340 TRACE("Additionally dirtifying stage %d\n", i
);
4341 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4343 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4344 TRACE("New lowest disabled: %d\n", Stage
);
4345 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4346 /* Previously disabled stage enabled. Stages above it may need enabling
4347 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4348 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4350 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4353 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4354 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4357 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4358 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4360 This
->stateBlock
->lowest_disabled_stage
= i
;
4361 TRACE("New lowest disabled: %d\n", i
);
4363 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4364 /* TODO: Built a stage -> texture unit mapping for register combiners */
4368 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4373 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4374 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4375 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4376 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4383 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4384 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4385 IWineD3DBaseTexture
*oldTexture
;
4387 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4389 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4390 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4393 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4395 if(pTexture
!= NULL
) {
4396 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4398 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4399 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4400 return WINED3DERR_INVALIDCALL
;
4402 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4405 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4406 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4408 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4409 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4410 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4412 /* Handle recording of state blocks */
4413 if (This
->isRecordingState
) {
4414 TRACE("Recording... not performing anything\n");
4418 if(oldTexture
== pTexture
) {
4419 TRACE("App is setting the same texture again, nothing to do\n");
4423 /** NOTE: MSDN says that setTexture increases the reference count,
4424 * and that the application must set the texture back to null (or have a leaky application),
4425 * This means we should pass the refcount up to the parent
4426 *******************************/
4427 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4428 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4429 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4431 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4432 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4433 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4434 * so the COLOROP and ALPHAOP have to be dirtified.
4436 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4437 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4439 if(bindCount
== 1) {
4440 new->baseTexture
.sampler
= Stage
;
4442 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4446 if (NULL
!= oldTexture
) {
4447 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4448 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4450 IWineD3DBaseTexture_Release(oldTexture
);
4451 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4452 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4453 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4456 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4458 /* Have to do a search for the other sampler(s) where the texture is bound to
4459 * Shouldn't happen as long as apps bind a texture only to one stage
4461 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4462 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4463 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4464 old
->baseTexture
.sampler
= i
;
4471 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4476 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4477 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4479 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4481 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4482 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4485 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4487 IWineD3DBaseTexture_AddRef(*ppTexture
);
4489 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4497 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4498 IWineD3DSurface
**ppBackBuffer
) {
4499 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4500 IWineD3DSwapChain
*swapChain
;
4503 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4505 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4506 if (hr
== WINED3D_OK
) {
4507 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4508 IWineD3DSwapChain_Release(swapChain
);
4510 *ppBackBuffer
= NULL
;
4515 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4516 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4517 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4518 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4521 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4523 IWineD3DSwapChain
*swapChain
;
4526 if(iSwapChain
> 0) {
4527 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4528 if (hr
== WINED3D_OK
) {
4529 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4530 IWineD3DSwapChain_Release(swapChain
);
4532 FIXME("(%p) Error getting display mode\n", This
);
4535 /* Don't read the real display mode,
4536 but return the stored mode instead. X11 can't change the color
4537 depth, and some apps are pretty angry if they SetDisplayMode from
4538 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4540 Also don't relay to the swapchain because with ddraw it's possible
4541 that there isn't a swapchain at all */
4542 pMode
->Width
= This
->ddraw_width
;
4543 pMode
->Height
= This
->ddraw_height
;
4544 pMode
->Format
= This
->ddraw_format
;
4545 pMode
->RefreshRate
= 0;
4552 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4553 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4554 TRACE("(%p)->(%p)\n", This
, hWnd
);
4556 if(This
->ddraw_fullscreen
) {
4557 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4558 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4560 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4561 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4565 This
->ddraw_window
= hWnd
;
4569 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4571 TRACE("(%p)->(%p)\n", This
, hWnd
);
4573 *hWnd
= This
->ddraw_window
;
4578 * Stateblock related functions
4581 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4583 IWineD3DStateBlockImpl
*object
;
4584 HRESULT temp_result
;
4587 TRACE("(%p)\n", This
);
4589 if (This
->isRecordingState
) {
4590 return WINED3DERR_INVALIDCALL
;
4593 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4594 if (NULL
== object
) {
4595 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4596 return E_OUTOFMEMORY
;
4598 TRACE("(%p) created object %p\n", This
, object
);
4599 object
->wineD3DDevice
= This
;
4600 /** FIXME: object->parent = parent; **/
4601 object
->parent
= NULL
;
4602 object
->blockType
= WINED3DSBT_RECORDED
;
4604 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4606 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4607 list_init(&object
->lightMap
[i
]);
4610 temp_result
= allocate_shader_constants(object
);
4611 if (WINED3D_OK
!= temp_result
)
4614 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4615 This
->updateStateBlock
= object
;
4616 This
->isRecordingState
= TRUE
;
4618 TRACE("(%p) recording stateblock %p\n",This
, object
);
4622 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4623 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4625 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4627 if (!This
->isRecordingState
) {
4628 FIXME("(%p) not recording! returning error\n", This
);
4629 *ppStateBlock
= NULL
;
4630 return WINED3DERR_INVALIDCALL
;
4633 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4634 if(object
->changed
.renderState
[i
]) {
4635 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4636 object
->num_contained_render_states
++;
4639 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4640 if(object
->changed
.transform
[i
]) {
4641 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4642 object
->num_contained_transform_states
++;
4645 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4646 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4647 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4648 object
->num_contained_vs_consts_f
++;
4651 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4652 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4653 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4654 object
->num_contained_vs_consts_i
++;
4657 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4658 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4659 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4660 object
->num_contained_vs_consts_b
++;
4663 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4664 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4665 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4666 object
->num_contained_ps_consts_i
++;
4669 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4670 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4671 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4672 object
->num_contained_ps_consts_b
++;
4675 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4676 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4677 if(object
->changed
.textureState
[i
][j
]) {
4678 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4679 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4680 object
->num_contained_tss_states
++;
4684 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4685 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4686 if(object
->changed
.samplerState
[i
][j
]) {
4687 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4688 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4689 object
->num_contained_sampler_states
++;
4694 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4695 This
->isRecordingState
= FALSE
;
4696 This
->updateStateBlock
= This
->stateBlock
;
4697 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4698 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4699 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4704 * Scene related functions
4706 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4707 /* At the moment we have no need for any functionality at the beginning
4709 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4710 TRACE("(%p)\n", This
);
4713 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4714 return WINED3DERR_INVALIDCALL
;
4716 This
->inScene
= TRUE
;
4720 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4721 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4722 TRACE("(%p)\n", This
);
4724 if(!This
->inScene
) {
4725 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4726 return WINED3DERR_INVALIDCALL
;
4729 if(This
->createParms
.BehaviorFlags
& WINED3DCREATE_MULTITHREADED
) {
4730 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4732 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4735 checkGLcall("glFlush");
4738 This
->inScene
= FALSE
;
4742 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4743 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4744 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4745 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4746 IWineD3DSwapChain
*swapChain
= NULL
;
4748 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4750 TRACE("(%p) Presenting the frame\n", This
);
4752 for(i
= 0 ; i
< swapchains
; i
++) {
4754 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4755 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4756 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4757 IWineD3DSwapChain_Release(swapChain
);
4763 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4764 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4765 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4766 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4768 GLbitfield glMask
= 0;
4770 CONST WINED3DRECT
* curRect
;
4772 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4773 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4775 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4776 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4777 /* TODO: What about depth stencil buffers without stencil bits? */
4778 return WINED3DERR_INVALIDCALL
;
4781 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4782 * and not the last active one.
4784 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_CLEAR
);
4787 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4788 apply_fbo_state(iface
);
4791 if (Count
> 0 && pRects
) {
4797 /* Only set the values up once, as they are not changing */
4798 if (Flags
& WINED3DCLEAR_STENCIL
) {
4799 glClearStencil(Stencil
);
4800 checkGLcall("glClearStencil");
4801 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4802 glStencilMask(0xFFFFFFFF);
4805 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4806 glDepthMask(GL_TRUE
);
4808 checkGLcall("glClearDepth");
4809 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4810 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4813 if (Flags
& WINED3DCLEAR_TARGET
) {
4814 TRACE("Clearing screen with glClear to color %x\n", Color
);
4815 glClearColor(D3DCOLOR_R(Color
),
4819 checkGLcall("glClearColor");
4821 /* Clear ALL colors! */
4822 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4823 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4827 /* In drawable flag is set below */
4829 if (This
->render_offscreen
) {
4830 glScissor(This
->stateBlock
->viewport
.X
,
4831 This
->stateBlock
->viewport
.Y
,
4832 This
->stateBlock
->viewport
.Width
,
4833 This
->stateBlock
->viewport
.Height
);
4835 glScissor(This
->stateBlock
->viewport
.X
,
4836 (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
-
4837 (This
->stateBlock
->viewport
.Y
+ This
->stateBlock
->viewport
.Height
)),
4838 This
->stateBlock
->viewport
.Width
,
4839 This
->stateBlock
->viewport
.Height
);
4841 checkGLcall("glScissor");
4843 checkGLcall("glClear");
4845 if(!(target
->Flags
& SFLAG_INDRAWABLE
) &&
4846 !(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& This
->render_offscreen
&& target
->Flags
& SFLAG_INTEXTURE
)) {
4848 if(curRect
[0].x1
> 0 || curRect
[0].y1
> 0 ||
4849 curRect
[0].x2
< target
->currentDesc
.Width
||
4850 curRect
[0].y2
< target
->currentDesc
.Height
) {
4851 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4852 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4856 /* Now process each rect in turn */
4857 for (i
= 0; i
< Count
; i
++) {
4858 /* Note gl uses lower left, width/height */
4859 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
, curRect
,
4860 curRect
[i
].x1
, curRect
[i
].y1
, curRect
[i
].x2
, curRect
[i
].y2
,
4861 curRect
[i
].x1
, (target
->currentDesc
.Height
- curRect
[i
].y2
),
4862 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4864 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4865 * The rectangle is not cleared, no error is returned, but further rectanlges are
4866 * still cleared if they are valid
4868 if(curRect
[i
].x1
> curRect
[i
].x2
|| curRect
[i
].y1
> curRect
[i
].y2
) {
4869 TRACE("Rectangle with negative dimensions, ignoring\n");
4873 if(This
->render_offscreen
) {
4874 glScissor(curRect
[i
].x1
, curRect
[i
].y1
,
4875 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4877 glScissor(curRect
[i
].x1
, target
->currentDesc
.Height
- curRect
[i
].y2
,
4878 curRect
[i
].x2
- curRect
[i
].x1
, curRect
[i
].y2
- curRect
[i
].y1
);
4880 checkGLcall("glScissor");
4883 checkGLcall("glClear");
4887 /* Restore the old values (why..?) */
4888 if (Flags
& WINED3DCLEAR_STENCIL
) {
4889 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4891 if (Flags
& WINED3DCLEAR_TARGET
) {
4892 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4893 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4894 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4895 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4896 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4901 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4902 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4904 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
4905 /* TODO: Move the fbo logic into ModifyLocation() */
4906 if(This
->render_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4907 target
->Flags
|= SFLAG_INTEXTURE
;
4915 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4916 UINT PrimitiveCount
) {
4918 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4920 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4921 debug_d3dprimitivetype(PrimitiveType
),
4922 StartVertex
, PrimitiveCount
);
4924 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4925 if(This
->stateBlock
->streamIsUP
) {
4926 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4927 This
->stateBlock
->streamIsUP
= FALSE
;
4930 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4931 This
->stateBlock
->loadBaseVertexIndex
= 0;
4932 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4934 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4935 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4936 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4940 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4941 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4942 WINED3DPRIMITIVETYPE PrimitiveType
,
4943 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4945 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4947 IWineD3DIndexBuffer
*pIB
;
4948 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4951 pIB
= This
->stateBlock
->pIndexData
;
4953 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4954 * without an index buffer set. (The first time at least...)
4955 * D3D8 simply dies, but I doubt it can do much harm to return
4956 * D3DERR_INVALIDCALL there as well. */
4957 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4958 return WINED3DERR_INVALIDCALL
;
4961 if(This
->stateBlock
->streamIsUP
) {
4962 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4963 This
->stateBlock
->streamIsUP
= FALSE
;
4965 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
4967 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
4968 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4969 minIndex
, NumVertices
, startIndex
, primCount
);
4971 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
4972 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
4978 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4979 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4980 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4983 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
4984 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
4989 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4990 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
4991 UINT VertexStreamZeroStride
) {
4992 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4993 IWineD3DVertexBuffer
*vb
;
4995 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
4996 debug_d3dprimitivetype(PrimitiveType
),
4997 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4999 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5000 vb
= This
->stateBlock
->streamSource
[0];
5001 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5002 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5003 This
->stateBlock
->streamOffset
[0] = 0;
5004 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5005 This
->stateBlock
->streamIsUP
= TRUE
;
5006 This
->stateBlock
->loadBaseVertexIndex
= 0;
5008 /* TODO: Only mark dirty if drawing from a different UP address */
5009 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5011 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5012 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5014 /* MSDN specifies stream zero settings must be set to NULL */
5015 This
->stateBlock
->streamStride
[0] = 0;
5016 This
->stateBlock
->streamSource
[0] = NULL
;
5018 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5019 * the new stream sources or use UP drawing again
5024 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5025 UINT MinVertexIndex
, UINT NumVertices
,
5026 UINT PrimitiveCount
, CONST
void* pIndexData
,
5027 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5028 UINT VertexStreamZeroStride
) {
5030 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5031 IWineD3DVertexBuffer
*vb
;
5032 IWineD3DIndexBuffer
*ib
;
5034 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5035 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5036 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5037 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5039 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5045 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5046 vb
= This
->stateBlock
->streamSource
[0];
5047 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5048 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5049 This
->stateBlock
->streamIsUP
= TRUE
;
5050 This
->stateBlock
->streamOffset
[0] = 0;
5051 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5053 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5054 This
->stateBlock
->baseVertexIndex
= 0;
5055 This
->stateBlock
->loadBaseVertexIndex
= 0;
5056 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5057 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5058 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5060 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5062 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5063 This
->stateBlock
->streamSource
[0] = NULL
;
5064 This
->stateBlock
->streamStride
[0] = 0;
5065 ib
= This
->stateBlock
->pIndexData
;
5067 IWineD3DIndexBuffer_Release(ib
);
5068 This
->stateBlock
->pIndexData
= NULL
;
5070 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5071 * SetStreamSource to specify a vertex buffer
5077 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5078 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5080 /* Mark the state dirty until we have nicer tracking
5081 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5084 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5085 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5086 This
->stateBlock
->baseVertexIndex
= 0;
5087 This
->up_strided
= DrawPrimStrideData
;
5088 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5089 This
->up_strided
= NULL
;
5093 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5094 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5095 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5097 /* Mark the state dirty until we have nicer tracking
5098 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5101 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5102 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5103 This
->stateBlock
->streamIsUP
= TRUE
;
5104 This
->stateBlock
->baseVertexIndex
= 0;
5105 This
->up_strided
= DrawPrimStrideData
;
5106 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5107 This
->up_strided
= NULL
;
5111 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5112 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5113 * not callable by the app directly no parameter validation checks are needed here.
5115 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5116 WINED3DLOCKED_BOX src
;
5117 WINED3DLOCKED_BOX dst
;
5119 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5121 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5122 * dirtification to improve loading performance.
5124 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5125 if(FAILED(hr
)) return hr
;
5126 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5128 IWineD3DVolume_UnlockBox(pSourceVolume
);
5132 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5134 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5136 IWineD3DVolume_UnlockBox(pSourceVolume
);
5138 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5143 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5144 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5145 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5146 HRESULT hr
= WINED3D_OK
;
5147 WINED3DRESOURCETYPE sourceType
;
5148 WINED3DRESOURCETYPE destinationType
;
5151 /* TODO: think about moving the code into IWineD3DBaseTexture */
5153 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5155 /* verify that the source and destination textures aren't NULL */
5156 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5157 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5158 This
, pSourceTexture
, pDestinationTexture
);
5159 hr
= WINED3DERR_INVALIDCALL
;
5162 if (pSourceTexture
== pDestinationTexture
) {
5163 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5164 This
, pSourceTexture
, pDestinationTexture
);
5165 hr
= WINED3DERR_INVALIDCALL
;
5167 /* Verify that the source and destination textures are the same type */
5168 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5169 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5171 if (sourceType
!= destinationType
) {
5172 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5174 hr
= WINED3DERR_INVALIDCALL
;
5177 /* check that both textures have the identical numbers of levels */
5178 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5179 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5180 hr
= WINED3DERR_INVALIDCALL
;
5183 if (WINED3D_OK
== hr
) {
5185 /* Make sure that the destination texture is loaded */
5186 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5188 /* Update every surface level of the texture */
5189 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5191 switch (sourceType
) {
5192 case WINED3DRTYPE_TEXTURE
:
5194 IWineD3DSurface
*srcSurface
;
5195 IWineD3DSurface
*destSurface
;
5197 for (i
= 0 ; i
< levels
; ++i
) {
5198 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5199 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5200 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5201 IWineD3DSurface_Release(srcSurface
);
5202 IWineD3DSurface_Release(destSurface
);
5203 if (WINED3D_OK
!= hr
) {
5204 WARN("(%p) : Call to update surface failed\n", This
);
5210 case WINED3DRTYPE_CUBETEXTURE
:
5212 IWineD3DSurface
*srcSurface
;
5213 IWineD3DSurface
*destSurface
;
5214 WINED3DCUBEMAP_FACES faceType
;
5216 for (i
= 0 ; i
< levels
; ++i
) {
5217 /* Update each cube face */
5218 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5219 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5220 if (WINED3D_OK
!= hr
) {
5221 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5223 TRACE("Got srcSurface %p\n", srcSurface
);
5225 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5226 if (WINED3D_OK
!= hr
) {
5227 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5229 TRACE("Got desrSurface %p\n", destSurface
);
5231 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5232 IWineD3DSurface_Release(srcSurface
);
5233 IWineD3DSurface_Release(destSurface
);
5234 if (WINED3D_OK
!= hr
) {
5235 WARN("(%p) : Call to update surface failed\n", This
);
5243 case WINED3DRTYPE_VOLUMETEXTURE
:
5245 IWineD3DVolume
*srcVolume
= NULL
;
5246 IWineD3DVolume
*destVolume
= NULL
;
5248 for (i
= 0 ; i
< levels
; ++i
) {
5249 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5250 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5251 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5252 IWineD3DVolume_Release(srcVolume
);
5253 IWineD3DVolume_Release(destVolume
);
5254 if (WINED3D_OK
!= hr
) {
5255 WARN("(%p) : Call to update volume failed\n", This
);
5263 FIXME("(%p) : Unsupported source and destination type\n", This
);
5264 hr
= WINED3DERR_INVALIDCALL
;
5271 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5272 IWineD3DSwapChain
*swapChain
;
5274 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5275 if(hr
== WINED3D_OK
) {
5276 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5277 IWineD3DSwapChain_Release(swapChain
);
5282 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5283 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5284 /* return a sensible default */
5286 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5287 FIXME("(%p) : stub\n", This
);
5291 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5292 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5294 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5295 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5296 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5297 return WINED3DERR_INVALIDCALL
;
5299 for (j
= 0; j
< 256; ++j
) {
5300 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5301 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5302 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5303 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5305 TRACE("(%p) : returning\n", This
);
5309 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5310 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5312 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5313 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5314 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5315 return WINED3DERR_INVALIDCALL
;
5317 for (j
= 0; j
< 256; ++j
) {
5318 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5319 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5320 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5321 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5323 TRACE("(%p) : returning\n", This
);
5327 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5329 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5330 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5331 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5332 return WINED3DERR_INVALIDCALL
;
5334 /*TODO: stateblocks */
5335 This
->currentPalette
= PaletteNumber
;
5336 TRACE("(%p) : returning\n", This
);
5340 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5341 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5342 if (PaletteNumber
== NULL
) {
5343 WARN("(%p) : returning Invalid Call\n", This
);
5344 return WINED3DERR_INVALIDCALL
;
5346 /*TODO: stateblocks */
5347 *PaletteNumber
= This
->currentPalette
;
5348 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5352 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5353 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5354 static BOOL showFixmes
= TRUE
;
5356 FIXME("(%p) : stub\n", This
);
5360 This
->softwareVertexProcessing
= bSoftware
;
5365 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5366 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5367 static BOOL showFixmes
= TRUE
;
5369 FIXME("(%p) : stub\n", This
);
5372 return This
->softwareVertexProcessing
;
5376 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5377 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5378 IWineD3DSwapChain
*swapChain
;
5381 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5383 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5384 if(hr
== WINED3D_OK
){
5385 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5386 IWineD3DSwapChain_Release(swapChain
);
5388 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5394 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5395 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5396 static BOOL showfixmes
= TRUE
;
5397 if(nSegments
!= 0.0f
) {
5399 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5406 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5407 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5408 static BOOL showfixmes
= TRUE
;
5410 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5416 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5417 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5418 /** TODO: remove casts to IWineD3DSurfaceImpl
5419 * NOTE: move code to surface to accomplish this
5420 ****************************************/
5421 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5422 int srcWidth
, srcHeight
;
5423 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5424 WINED3DFORMAT destFormat
, srcFormat
;
5426 int srcLeft
, destLeft
, destTop
;
5427 WINED3DPOOL srcPool
, destPool
;
5429 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5430 glDescriptor
*glDescription
= NULL
;
5433 CONVERT_TYPES convert
= NO_CONVERSION
;
5435 WINED3DSURFACE_DESC winedesc
;
5437 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5438 memset(&winedesc
, 0, sizeof(winedesc
));
5439 winedesc
.Width
= &srcSurfaceWidth
;
5440 winedesc
.Height
= &srcSurfaceHeight
;
5441 winedesc
.Pool
= &srcPool
;
5442 winedesc
.Format
= &srcFormat
;
5444 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5446 winedesc
.Width
= &destSurfaceWidth
;
5447 winedesc
.Height
= &destSurfaceHeight
;
5448 winedesc
.Pool
= &destPool
;
5449 winedesc
.Format
= &destFormat
;
5450 winedesc
.Size
= &destSize
;
5452 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5454 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5455 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5456 return WINED3DERR_INVALIDCALL
;
5459 /* This call loads the opengl surface directly, instead of copying the surface to the
5460 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5461 * copy in sysmem and use regular surface loading.
5463 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5464 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5465 if(convert
!= NO_CONVERSION
) {
5466 return IWineD3DSurface_BltFast(pDestinationSurface
,
5467 pDestPoint
? pDestPoint
->x
: 0,
5468 pDestPoint
? pDestPoint
->y
: 0,
5469 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5472 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5473 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5474 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5476 /* Get the update surface description */
5477 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5480 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5484 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5485 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5486 checkGLcall("glActiveTextureARB");
5489 /* Make sure the surface is loaded and up to date */
5490 IWineD3DSurface_PreLoad(pDestinationSurface
);
5492 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5494 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5495 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5496 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5497 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5498 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5499 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5502 /* This function doesn't support compressed textures
5503 the pitch is just bytesPerPixel * width */
5504 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5505 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5506 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5507 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5509 /* TODO DXT formats */
5511 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5512 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5514 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5516 ,glDescription
->level
5521 ,glDescription
->glFormat
5522 ,glDescription
->glType
5523 ,IWineD3DSurface_GetData(pSourceSurface
)
5527 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5529 /* need to lock the surface to get the data */
5530 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5533 /* TODO: Cube and volume support */
5535 /* not a whole row so we have to do it a line at a time */
5538 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5539 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5541 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5543 glTexSubImage2D(glDescription
->target
5544 ,glDescription
->level
5549 ,glDescription
->glFormat
5550 ,glDescription
->glType
5551 ,data
/* could be quicker using */
5556 } else { /* Full width, so just write out the whole texture */
5558 if (WINED3DFMT_DXT1
== destFormat
||
5559 WINED3DFMT_DXT2
== destFormat
||
5560 WINED3DFMT_DXT3
== destFormat
||
5561 WINED3DFMT_DXT4
== destFormat
||
5562 WINED3DFMT_DXT5
== destFormat
) {
5563 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5564 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5565 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5566 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5567 } if (destFormat
!= srcFormat
) {
5568 FIXME("Updating mixed format compressed texture is not curretly support\n");
5570 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5571 glDescription
->level
,
5572 glDescription
->glFormatInternal
,
5577 IWineD3DSurface_GetData(pSourceSurface
));
5580 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5585 glTexSubImage2D(glDescription
->target
5586 ,glDescription
->level
5591 ,glDescription
->glFormat
5592 ,glDescription
->glType
5593 ,IWineD3DSurface_GetData(pSourceSurface
)
5597 checkGLcall("glTexSubImage2D");
5601 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5602 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
5607 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5608 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5609 struct WineD3DRectPatch
*patch
;
5613 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5615 if(!(Handle
|| pRectPatchInfo
)) {
5616 /* TODO: Write a test for the return value, thus the FIXME */
5617 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5618 return WINED3DERR_INVALIDCALL
;
5622 i
= PATCHMAP_HASHFUNC(Handle
);
5624 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5625 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5626 if(patch
->Handle
== Handle
) {
5633 TRACE("Patch does not exist. Creating a new one\n");
5634 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5635 patch
->Handle
= Handle
;
5636 list_add_head(&This
->patches
[i
], &patch
->entry
);
5638 TRACE("Found existing patch %p\n", patch
);
5641 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5642 * attributes we have to tesselate, read back, and draw. This needs a patch
5643 * management structure instance. Create one.
5645 * A possible improvement is to check if a vertex shader is used, and if not directly
5648 FIXME("Drawing an uncached patch. This is slow\n");
5649 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5652 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5653 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5654 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5656 TRACE("Tesselation density or patch info changed, retesselating\n");
5658 if(pRectPatchInfo
) {
5659 memcpy(&patch
->RectPatchInfo
, pRectPatchInfo
, sizeof(*pRectPatchInfo
));
5661 patch
->numSegs
[0] = pNumSegs
[0];
5662 patch
->numSegs
[1] = pNumSegs
[1];
5663 patch
->numSegs
[2] = pNumSegs
[2];
5664 patch
->numSegs
[3] = pNumSegs
[3];
5666 hr
= tesselate_rectpatch(This
, patch
);
5668 WARN("Patch tesselation failed\n");
5670 /* Do not release the handle to store the params of the patch */
5672 HeapFree(GetProcessHeap(), 0, patch
);
5678 This
->currentPatch
= patch
;
5679 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
5680 This
->currentPatch
= NULL
;
5682 /* Destroy uncached patches */
5684 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5685 HeapFree(GetProcessHeap(), 0, patch
);
5690 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5691 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5692 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5693 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5694 FIXME("(%p) : Stub\n", This
);
5698 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5699 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5701 struct WineD3DRectPatch
*patch
;
5703 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5705 i
= PATCHMAP_HASHFUNC(Handle
);
5706 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5707 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5708 if(patch
->Handle
== Handle
) {
5709 TRACE("Deleting patch %p\n", patch
);
5710 list_remove(&patch
->entry
);
5711 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5712 HeapFree(GetProcessHeap(), 0, patch
);
5717 /* TODO: Write a test for the return value */
5718 FIXME("Attempt to destroy nonexistant patch\n");
5719 return WINED3DERR_INVALIDCALL
;
5722 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5724 IWineD3DSwapChain
*swapchain
;
5726 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5727 if (SUCCEEDED(hr
)) {
5728 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5735 static void bind_fbo(IWineD3DDevice
*iface
, GLenum target
, GLuint
*fbo
) {
5736 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5739 GL_EXTCALL(glGenFramebuffersEXT(1, fbo
));
5740 checkGLcall("glGenFramebuffersEXT()");
5742 GL_EXTCALL(glBindFramebufferEXT(target
, *fbo
));
5743 checkGLcall("glBindFramebuffer()");
5746 static void attach_surface_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, DWORD idx
, IWineD3DSurface
*surface
) {
5747 const IWineD3DSurfaceImpl
*surface_impl
= (IWineD3DSurfaceImpl
*)surface
;
5748 IWineD3DBaseTextureImpl
*texture_impl
;
5749 GLenum texttarget
, target
;
5752 texttarget
= surface_impl
->glDescription
.target
;
5753 if(texttarget
== GL_TEXTURE_2D
) {
5754 target
= GL_TEXTURE_2D
;
5755 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5756 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
5757 target
= GL_TEXTURE_RECTANGLE_ARB
;
5758 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5760 target
= GL_TEXTURE_CUBE_MAP_ARB
;
5761 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5764 IWineD3DSurface_PreLoad(surface
);
5766 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5767 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5768 glBindTexture(target
, old_binding
);
5770 /* Update base texture states array */
5771 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
5772 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
5773 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
5774 if (texture_impl
->baseTexture
.bindCount
) {
5775 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
5778 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
5781 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
,
5782 surface_impl
->glDescription
.textureName
, surface_impl
->glDescription
.level
));
5784 checkGLcall("attach_surface_fbo");
5787 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
5788 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5789 IWineD3DSwapChain
*swapchain
;
5791 swapchain
= get_swapchain(surface
);
5795 TRACE("Surface %p is onscreen\n", surface
);
5797 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5798 buffer
= surface_get_gl_buffer(surface
, swapchain
);
5799 glDrawBuffer(buffer
);
5800 checkGLcall("glDrawBuffer()");
5802 TRACE("Surface %p is offscreen\n", surface
);
5803 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
5804 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
5808 glEnable(GL_SCISSOR_TEST
);
5810 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5812 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5813 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5815 checkGLcall("glScissor");
5817 glDisable(GL_SCISSOR_TEST
);
5819 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5821 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5822 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5824 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
5825 glClear(GL_COLOR_BUFFER_BIT
);
5826 checkGLcall("glClear");
5828 if (This
->render_offscreen
) {
5829 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
5831 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5832 checkGLcall("glBindFramebuffer()");
5835 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
5836 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
5837 glDrawBuffer(GL_BACK
);
5838 checkGLcall("glDrawBuffer()");
5842 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5843 unsigned int r
, g
, b
, a
;
5846 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
5847 destfmt
== WINED3DFMT_R8G8B8
)
5850 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5852 a
= (color
& 0xff000000) >> 24;
5853 r
= (color
& 0x00ff0000) >> 16;
5854 g
= (color
& 0x0000ff00) >> 8;
5855 b
= (color
& 0x000000ff) >> 0;
5859 case WINED3DFMT_R5G6B5
:
5860 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5867 TRACE("Returning %08x\n", ret
);
5870 case WINED3DFMT_X1R5G5B5
:
5871 case WINED3DFMT_A1R5G5B5
:
5880 TRACE("Returning %08x\n", ret
);
5884 TRACE("Returning %08x\n", a
);
5887 case WINED3DFMT_X4R4G4B4
:
5888 case WINED3DFMT_A4R4G4B4
:
5897 TRACE("Returning %08x\n", ret
);
5900 case WINED3DFMT_R3G3B2
:
5907 TRACE("Returning %08x\n", ret
);
5910 case WINED3DFMT_X8B8G8R8
:
5911 case WINED3DFMT_A8B8G8R8
:
5916 TRACE("Returning %08x\n", ret
);
5919 case WINED3DFMT_A2R10G10B10
:
5921 r
= (r
* 1024) / 256;
5922 g
= (g
* 1024) / 256;
5923 b
= (b
* 1024) / 256;
5928 TRACE("Returning %08x\n", ret
);
5931 case WINED3DFMT_A2B10G10R10
:
5933 r
= (r
* 1024) / 256;
5934 g
= (g
* 1024) / 256;
5935 b
= (b
* 1024) / 256;
5940 TRACE("Returning %08x\n", ret
);
5944 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5949 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5950 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5951 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5953 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
5955 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5956 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5957 return WINED3DERR_INVALIDCALL
;
5960 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5961 color_fill_fbo(iface
, pSurface
, pRect
, color
);
5964 /* Just forward this to the DirectDraw blitting engine */
5965 memset(&BltFx
, 0, sizeof(BltFx
));
5966 BltFx
.dwSize
= sizeof(BltFx
);
5967 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
5968 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
5972 /* rendertarget and deptth stencil functions */
5973 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5974 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5976 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5977 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5978 return WINED3DERR_INVALIDCALL
;
5981 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5982 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5983 /* Note inc ref on returned surface */
5984 if(*ppRenderTarget
!= NULL
)
5985 IWineD3DSurface_AddRef(*ppRenderTarget
);
5989 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
5990 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5991 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5992 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5993 IWineD3DSwapChainImpl
*Swapchain
;
5996 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
5998 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5999 if(hr
!= WINED3D_OK
) {
6000 ERR("Can't get the swapchain\n");
6004 /* Make sure to release the swapchain */
6005 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6007 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6008 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6009 return WINED3DERR_INVALIDCALL
;
6011 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6012 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6013 return WINED3DERR_INVALIDCALL
;
6016 if(Swapchain
->frontBuffer
!= Front
) {
6017 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6019 if(Swapchain
->frontBuffer
)
6020 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6021 Swapchain
->frontBuffer
= Front
;
6023 if(Swapchain
->frontBuffer
) {
6024 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6028 if(Back
&& !Swapchain
->backBuffer
) {
6029 /* We need memory for the back buffer array - only one back buffer this way */
6030 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6031 if(!Swapchain
->backBuffer
) {
6032 ERR("Out of memory\n");
6033 return E_OUTOFMEMORY
;
6037 if(Swapchain
->backBuffer
[0] != Back
) {
6038 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6040 /* What to do about the context here in the case of multithreading? Not sure.
6041 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6044 if(!Swapchain
->backBuffer
[0]) {
6045 /* GL was told to draw to the front buffer at creation,
6048 glDrawBuffer(GL_BACK
);
6049 checkGLcall("glDrawBuffer(GL_BACK)");
6050 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6051 Swapchain
->presentParms
.BackBufferCount
= 1;
6053 /* That makes problems - disable for now */
6054 /* glDrawBuffer(GL_FRONT); */
6055 checkGLcall("glDrawBuffer(GL_FRONT)");
6056 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6057 Swapchain
->presentParms
.BackBufferCount
= 0;
6061 if(Swapchain
->backBuffer
[0])
6062 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6063 Swapchain
->backBuffer
[0] = Back
;
6065 if(Swapchain
->backBuffer
[0]) {
6066 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6068 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6069 Swapchain
->backBuffer
= NULL
;
6077 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6078 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6079 *ppZStencilSurface
= This
->stencilBufferTarget
;
6080 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6082 if(*ppZStencilSurface
!= NULL
) {
6083 /* Note inc ref on returned surface */
6084 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6087 return WINED3DERR_NOTFOUND
;
6091 /* TODO: Handle stencil attachments */
6092 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
6093 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6094 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
6096 TRACE("Set depth stencil to %p\n", depth_stencil
);
6098 if (depth_stencil_impl
) {
6099 if (depth_stencil_impl
->current_renderbuffer
) {
6100 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, depth_stencil_impl
->current_renderbuffer
->id
));
6101 checkGLcall("glFramebufferRenderbufferEXT()");
6103 IWineD3DBaseTextureImpl
*texture_impl
;
6104 GLenum texttarget
, target
;
6105 GLint old_binding
= 0;
6107 texttarget
= depth_stencil_impl
->glDescription
.target
;
6108 if(texttarget
== GL_TEXTURE_2D
) {
6109 target
= GL_TEXTURE_2D
;
6110 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
6111 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
6112 target
= GL_TEXTURE_RECTANGLE_ARB
;
6113 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
6115 target
= GL_TEXTURE_CUBE_MAP_ARB
;
6116 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6119 IWineD3DSurface_PreLoad(depth_stencil
);
6121 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6122 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6123 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
6124 glBindTexture(target
, old_binding
);
6126 /* Update base texture states array */
6127 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6128 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6129 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6130 if (texture_impl
->baseTexture
.bindCount
) {
6131 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6134 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6137 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
,
6138 depth_stencil_impl
->glDescription
.textureName
, depth_stencil_impl
->glDescription
.level
));
6139 checkGLcall("glFramebufferTexture2DEXT()");
6142 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
6143 checkGLcall("glFramebufferTexture2DEXT()");
6147 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
6148 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6149 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
6151 TRACE("Set render target %u to %p\n", idx
, render_target
);
6154 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, idx
, render_target
);
6155 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
6157 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
6158 checkGLcall("glFramebufferTexture2DEXT()");
6160 This
->draw_buffers
[idx
] = GL_NONE
;
6164 static void check_fbo_status(IWineD3DDevice
*iface
) {
6165 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6168 status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
6169 if (status
== GL_FRAMEBUFFER_COMPLETE_EXT
) {
6170 TRACE("FBO complete\n");
6172 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status
), status
);
6174 /* Dump the FBO attachments */
6175 if (status
== GL_FRAMEBUFFER_UNSUPPORTED_EXT
) {
6176 IWineD3DSurfaceImpl
*attachment
;
6179 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6180 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_color_attachments
[i
];
6182 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i
, attachment
, debug_d3dformat(attachment
->resource
.format
),
6183 attachment
->pow2Width
, attachment
->pow2Height
);
6186 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_depth_attachment
;
6188 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment
, debug_d3dformat(attachment
->resource
.format
),
6189 attachment
->pow2Width
, attachment
->pow2Height
);
6195 static BOOL
depth_mismatch_fbo(IWineD3DDevice
*iface
) {
6196 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6197 IWineD3DSurfaceImpl
*rt_impl
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
6198 IWineD3DSurfaceImpl
*ds_impl
= (IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
;
6200 if (!ds_impl
) return FALSE
;
6202 if (ds_impl
->current_renderbuffer
) {
6203 return (rt_impl
->pow2Width
!= ds_impl
->current_renderbuffer
->width
||
6204 rt_impl
->pow2Height
!= ds_impl
->current_renderbuffer
->height
);
6207 return (rt_impl
->pow2Width
!= ds_impl
->pow2Width
||
6208 rt_impl
->pow2Height
!= ds_impl
->pow2Height
);
6211 void apply_fbo_state(IWineD3DDevice
*iface
) {
6212 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6215 if (This
->render_offscreen
) {
6216 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6218 /* Apply render targets */
6219 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6220 IWineD3DSurface
*render_target
= This
->render_targets
[i
];
6221 if (This
->fbo_color_attachments
[i
] != render_target
) {
6222 set_render_target_fbo(iface
, i
, render_target
);
6223 This
->fbo_color_attachments
[i
] = render_target
;
6227 /* Apply depth targets */
6228 if (This
->fbo_depth_attachment
!= This
->stencilBufferTarget
|| depth_mismatch_fbo(iface
)) {
6229 unsigned int w
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Width
;
6230 unsigned int h
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Height
;
6232 if (This
->stencilBufferTarget
) {
6233 surface_set_compatible_renderbuffer(This
->stencilBufferTarget
, w
, h
);
6235 set_depth_stencil_fbo(iface
, This
->stencilBufferTarget
);
6236 This
->fbo_depth_attachment
= This
->stencilBufferTarget
;
6239 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
6240 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
6241 checkGLcall("glDrawBuffers()");
6243 glDrawBuffer(This
->draw_buffers
[0]);
6244 checkGLcall("glDrawBuffer()");
6247 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6250 check_fbo_status(iface
);
6253 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6254 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6255 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6256 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6257 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6260 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6261 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6262 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6263 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6266 case WINED3DTEXF_LINEAR
:
6267 gl_filter
= GL_LINEAR
;
6271 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6272 case WINED3DTEXF_NONE
:
6273 case WINED3DTEXF_POINT
:
6274 gl_filter
= GL_NEAREST
;
6278 /* Attach src surface to src fbo */
6279 src_swapchain
= get_swapchain(src_surface
);
6280 if (src_swapchain
) {
6283 TRACE("Source surface %p is onscreen\n", src_surface
);
6284 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6287 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6288 buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6289 glReadBuffer(buffer
);
6290 checkGLcall("glReadBuffer()");
6292 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6293 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6295 TRACE("Source surface %p is offscreen\n", src_surface
);
6297 bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->src_fbo
);
6298 attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6299 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6300 checkGLcall("glReadBuffer()");
6304 /* Attach dst surface to dst fbo */
6305 dst_swapchain
= get_swapchain(dst_surface
);
6306 if (dst_swapchain
) {
6309 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6310 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6313 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6314 buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6315 glDrawBuffer(buffer
);
6316 checkGLcall("glDrawBuffer()");
6318 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6319 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6321 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6323 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6324 if(!src_swapchain
) {
6325 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6329 bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6330 attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6331 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6332 checkGLcall("glDrawBuffer()");
6334 glDisable(GL_SCISSOR_TEST
);
6335 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6338 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6339 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6340 checkGLcall("glBlitFramebuffer()");
6342 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6343 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6344 checkGLcall("glBlitFramebuffer()");
6347 if (This
->render_offscreen
) {
6348 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6350 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6351 checkGLcall("glBindFramebuffer()");
6354 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6355 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6356 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6357 glDrawBuffer(GL_BACK
);
6358 checkGLcall("glDrawBuffer()");
6363 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6364 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6365 WINED3DVIEWPORT viewport
;
6367 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6369 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6370 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6371 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6372 return WINED3DERR_INVALIDCALL
;
6375 /* MSDN says that null disables the render target
6376 but a device must always be associated with a render target
6377 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6379 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6382 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6383 FIXME("Trying to set render target 0 to NULL\n");
6384 return WINED3DERR_INVALIDCALL
;
6386 if (pRenderTarget
&& !((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
6387 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
);
6388 return WINED3DERR_INVALIDCALL
;
6391 /* If we are trying to set what we already have, don't bother */
6392 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6393 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6396 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6397 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6398 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6400 /* Render target 0 is special */
6401 if(RenderTargetIndex
== 0) {
6402 /* Finally, reset the viewport as the MSDN states. */
6403 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6404 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6407 viewport
.MaxZ
= 1.0f
;
6408 viewport
.MinZ
= 0.0f
;
6409 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6410 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6411 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6413 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6415 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6417 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6418 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6420 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6425 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6426 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6427 HRESULT hr
= WINED3D_OK
;
6428 IWineD3DSurface
*tmp
;
6430 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6432 if (pNewZStencil
== This
->stencilBufferTarget
) {
6433 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6435 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6436 * depending on the renter target implementation being used.
6437 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6438 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6439 * stencil buffer and incure an extra memory overhead
6440 ******************************************************/
6442 tmp
= This
->stencilBufferTarget
;
6443 This
->stencilBufferTarget
= pNewZStencil
;
6444 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
6445 /* should we be calling the parent or the wined3d surface? */
6446 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6447 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6450 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6451 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6452 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6453 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6454 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6461 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6462 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6463 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6464 /* TODO: the use of Impl is deprecated. */
6465 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6466 WINED3DLOCKED_RECT lockedRect
;
6468 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6470 /* some basic validation checks */
6471 if(This
->cursorTexture
) {
6472 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6474 glDeleteTextures(1, &This
->cursorTexture
);
6476 This
->cursorTexture
= 0;
6479 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6480 This
->haveHardwareCursor
= TRUE
;
6482 This
->haveHardwareCursor
= FALSE
;
6485 WINED3DLOCKED_RECT rect
;
6487 /* MSDN: Cursor must be A8R8G8B8 */
6488 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6489 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6490 return WINED3DERR_INVALIDCALL
;
6493 /* MSDN: Cursor must be smaller than the display mode */
6494 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6495 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6496 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
);
6497 return WINED3DERR_INVALIDCALL
;
6500 if (!This
->haveHardwareCursor
) {
6501 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6503 /* Do not store the surface's pointer because the application may
6504 * release it after setting the cursor image. Windows doesn't
6505 * addref the set surface, so we can't do this either without
6506 * creating circular refcount dependencies. Copy out the gl texture
6509 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6510 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6511 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6513 const GlPixelFormatDesc
*glDesc
;
6514 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6515 char *mem
, *bits
= (char *)rect
.pBits
;
6516 GLint intfmt
= glDesc
->glInternal
;
6517 GLint format
= glDesc
->glFormat
;
6518 GLint type
= glDesc
->glType
;
6519 INT height
= This
->cursorHeight
;
6520 INT width
= This
->cursorWidth
;
6521 INT bpp
= tableEntry
->bpp
;
6524 /* Reformat the texture memory (pitch and width can be
6526 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6527 for(i
= 0; i
< height
; i
++)
6528 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6529 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6532 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6533 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6534 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6537 /* Make sure that a proper texture unit is selected */
6538 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6539 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6540 checkGLcall("glActiveTextureARB");
6542 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
6543 /* Create a new cursor texture */
6544 glGenTextures(1, &This
->cursorTexture
);
6545 checkGLcall("glGenTextures");
6546 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6547 checkGLcall("glBindTexture");
6548 /* Copy the bitmap memory into the cursor texture */
6549 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6550 HeapFree(GetProcessHeap(), 0, mem
);
6551 checkGLcall("glTexImage2D");
6553 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6554 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6555 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6562 FIXME("A cursor texture was not returned.\n");
6563 This
->cursorTexture
= 0;
6568 /* Draw a hardware cursor */
6569 ICONINFO cursorInfo
;
6571 /* Create and clear maskBits because it is not needed for
6572 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6574 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6575 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6576 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6577 WINED3DLOCK_NO_DIRTY_UPDATE
|
6578 WINED3DLOCK_READONLY
6580 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6581 pSur
->currentDesc
.Height
);
6583 cursorInfo
.fIcon
= FALSE
;
6584 cursorInfo
.xHotspot
= XHotSpot
;
6585 cursorInfo
.yHotspot
= YHotSpot
;
6586 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6587 pSur
->currentDesc
.Height
, 1,
6589 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6590 pSur
->currentDesc
.Height
, 1,
6591 32, lockedRect
.pBits
);
6592 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6593 /* Create our cursor and clean up. */
6594 cursor
= CreateIconIndirect(&cursorInfo
);
6596 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6597 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6598 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6599 This
->hardwareCursor
= cursor
;
6600 HeapFree(GetProcessHeap(), 0, maskBits
);
6604 This
->xHotSpot
= XHotSpot
;
6605 This
->yHotSpot
= YHotSpot
;
6609 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6610 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6611 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6613 This
->xScreenSpace
= XScreenSpace
;
6614 This
->yScreenSpace
= YScreenSpace
;
6620 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6621 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6622 BOOL oldVisible
= This
->bCursorVisible
;
6625 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6628 * When ShowCursor is first called it should make the cursor appear at the OS's last
6629 * known cursor position. Because of this, some applications just repetitively call
6630 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6633 This
->xScreenSpace
= pt
.x
;
6634 This
->yScreenSpace
= pt
.y
;
6636 if (This
->haveHardwareCursor
) {
6637 This
->bCursorVisible
= bShow
;
6639 SetCursor(This
->hardwareCursor
);
6645 if (This
->cursorTexture
)
6646 This
->bCursorVisible
= bShow
;
6652 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6653 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6654 IWineD3DResourceImpl
*resource
;
6655 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6657 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6658 switch (This
->state
) {
6661 case WINED3DERR_DEVICELOST
:
6663 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6664 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
6665 return WINED3DERR_DEVICENOTRESET
;
6667 return WINED3DERR_DEVICELOST
;
6669 case WINED3DERR_DRIVERINTERNALERROR
:
6670 return WINED3DERR_DRIVERINTERNALERROR
;
6674 return WINED3DERR_DRIVERINTERNALERROR
;
6678 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6679 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6680 /** FIXME: Resource tracking needs to be done,
6681 * The closes we can do to this is set the priorities of all managed textures low
6682 * and then reset them.
6683 ***********************************************************/
6684 FIXME("(%p) : stub\n", This
);
6688 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6689 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6691 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6692 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6693 /* Release the DC */
6694 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6695 DeleteDC(surface
->hDC
);
6696 /* Release the DIB section */
6697 DeleteObject(surface
->dib
.DIBsection
);
6698 surface
->dib
.bitmap_data
= NULL
;
6699 surface
->resource
.allocatedMemory
= NULL
;
6700 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6702 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6703 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6704 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
6705 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6706 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6708 surface
->pow2Width
= surface
->pow2Height
= 1;
6709 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6710 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6712 if(surface
->glDescription
.textureName
) {
6713 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6715 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6717 surface
->glDescription
.textureName
= 0;
6718 surface
->Flags
&= ~SFLAG_CLIENT
;
6720 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6721 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6722 surface
->Flags
|= SFLAG_NONPOW2
;
6724 surface
->Flags
&= ~SFLAG_NONPOW2
;
6726 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
6727 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6730 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6732 IWineD3DSwapChainImpl
*swapchain
;
6734 BOOL DisplayModeChanged
= FALSE
;
6735 WINED3DDISPLAYMODE mode
;
6736 TRACE("(%p)\n", This
);
6738 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6740 ERR("Failed to get the first implicit swapchain\n");
6744 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6745 * on an existing gl context, so there's no real need for recreation.
6747 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6749 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6751 TRACE("New params:\n");
6752 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6753 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6754 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6755 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6756 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6757 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6758 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6759 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6760 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6761 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6762 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6763 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6764 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6766 /* No special treatment of these parameters. Just store them */
6767 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6768 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6769 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6770 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6772 /* What to do about these? */
6773 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6774 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6775 ERR("Cannot change the back buffer count yet\n");
6777 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6778 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6779 ERR("Cannot change the back buffer format yet\n");
6781 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6782 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6783 ERR("Cannot change the device window yet\n");
6785 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
6786 ERR("What do do about a changed auto depth stencil parameter?\n");
6789 if(pPresentationParameters
->Windowed
) {
6790 mode
.Width
= swapchain
->orig_width
;
6791 mode
.Height
= swapchain
->orig_height
;
6792 mode
.RefreshRate
= 0;
6793 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6795 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6796 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6797 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6798 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6801 /* Should Width == 800 && Height == 0 set 800x600? */
6802 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6803 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6804 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6811 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
6812 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
6816 if(!pPresentationParameters
->Windowed
) {
6817 DisplayModeChanged
= TRUE
;
6819 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6820 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6822 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6823 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6824 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6827 /* Now set the new viewport */
6828 IWineD3DDevice_SetViewport(iface
, &vp
);
6831 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6832 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6833 DisplayModeChanged
) {
6835 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6836 if(!pPresentationParameters
->Windowed
) {
6837 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
6840 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6842 /* Switching out of fullscreen mode? First set the original res, then change the window */
6843 if(pPresentationParameters
->Windowed
) {
6844 IWineD3DDevice_SetFullscreen(iface
, FALSE
);
6846 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6849 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6853 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6854 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6855 /** FIXME: always true at the moment **/
6856 if(!bEnableDialogs
) {
6857 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6863 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6864 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6865 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6867 *pParameters
= This
->createParms
;
6871 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6872 IWineD3DSwapChain
*swapchain
;
6873 HRESULT hrc
= WINED3D_OK
;
6875 TRACE("Relaying to swapchain\n");
6877 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6878 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
6879 IWineD3DSwapChain_Release(swapchain
);
6884 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6885 IWineD3DSwapChain
*swapchain
;
6886 HRESULT hrc
= WINED3D_OK
;
6888 TRACE("Relaying to swapchain\n");
6890 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6891 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6892 IWineD3DSwapChain_Release(swapchain
);
6898 /** ********************************************************
6899 * Notification functions
6900 ** ********************************************************/
6901 /** This function must be called in the release of a resource when ref == 0,
6902 * the contents of resource must still be correct,
6903 * any handels to other resource held by the caller must be closed
6904 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6905 *****************************************************/
6906 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6907 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6909 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
6910 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6913 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6914 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6916 TRACE("(%p) : Removing resource %p\n", This
, resource
);
6918 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6922 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6923 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6926 TRACE("(%p) : resource %p\n", This
, resource
);
6927 switch(IWineD3DResource_GetType(resource
)){
6928 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6929 case WINED3DRTYPE_SURFACE
: {
6932 /* Cleanup any FBO attachments if d3d is enabled */
6933 if(This
->d3d_initialized
) {
6934 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
6935 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
6937 TRACE("Last active render target destroyed\n");
6938 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6939 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6940 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6941 * and the lastActiveRenderTarget member shouldn't matter
6944 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
6945 TRACE("Activating primary back buffer\n");
6946 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
6947 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
6948 /* Single buffering environment */
6949 TRACE("Activating primary front buffer\n");
6950 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
6952 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6953 /* Implicit render target destroyed, that means the device is being destroyed
6954 * whatever we set here, it shouldn't matter
6956 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
6959 /* May happen during ddraw uninitialization */
6960 TRACE("Render target set, but swapchain does not exist!\n");
6961 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
6965 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6966 if (This
->fbo_color_attachments
[i
] == (IWineD3DSurface
*)resource
) {
6967 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6968 set_render_target_fbo(iface
, i
, NULL
);
6969 This
->fbo_color_attachments
[i
] = NULL
;
6972 if (This
->fbo_depth_attachment
== (IWineD3DSurface
*)resource
) {
6973 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6974 set_depth_stencil_fbo(iface
, NULL
);
6975 This
->fbo_depth_attachment
= NULL
;
6981 case WINED3DRTYPE_TEXTURE
:
6982 case WINED3DRTYPE_CUBETEXTURE
:
6983 case WINED3DRTYPE_VOLUMETEXTURE
:
6984 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6985 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6986 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6987 This
->stateBlock
->textures
[counter
] = NULL
;
6989 if (This
->updateStateBlock
!= This
->stateBlock
){
6990 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6991 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6992 This
->updateStateBlock
->textures
[counter
] = NULL
;
6997 case WINED3DRTYPE_VOLUME
:
6998 /* TODO: nothing really? */
7000 case WINED3DRTYPE_VERTEXBUFFER
:
7001 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7004 TRACE("Cleaning up stream pointers\n");
7006 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7007 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7008 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7010 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7011 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7012 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7013 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7014 /* Set changed flag? */
7017 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) */
7018 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7019 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7020 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7023 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7024 else { /* This shouldn't happen */
7025 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7032 case WINED3DRTYPE_INDEXBUFFER
:
7033 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7034 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7035 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7036 This
->updateStateBlock
->pIndexData
= NULL
;
7039 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7040 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7041 This
->stateBlock
->pIndexData
= NULL
;
7047 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7052 /* Remove the resoruce from the resourceStore */
7053 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7055 TRACE("Resource released\n");
7059 /**********************************************************
7060 * IWineD3DDevice VTbl follows
7061 **********************************************************/
7063 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7065 /*** IUnknown methods ***/
7066 IWineD3DDeviceImpl_QueryInterface
,
7067 IWineD3DDeviceImpl_AddRef
,
7068 IWineD3DDeviceImpl_Release
,
7069 /*** IWineD3DDevice methods ***/
7070 IWineD3DDeviceImpl_GetParent
,
7071 /*** Creation methods**/
7072 IWineD3DDeviceImpl_CreateVertexBuffer
,
7073 IWineD3DDeviceImpl_CreateIndexBuffer
,
7074 IWineD3DDeviceImpl_CreateStateBlock
,
7075 IWineD3DDeviceImpl_CreateSurface
,
7076 IWineD3DDeviceImpl_CreateTexture
,
7077 IWineD3DDeviceImpl_CreateVolumeTexture
,
7078 IWineD3DDeviceImpl_CreateVolume
,
7079 IWineD3DDeviceImpl_CreateCubeTexture
,
7080 IWineD3DDeviceImpl_CreateQuery
,
7081 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7082 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7083 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7084 IWineD3DDeviceImpl_CreateVertexShader
,
7085 IWineD3DDeviceImpl_CreatePixelShader
,
7086 IWineD3DDeviceImpl_CreatePalette
,
7087 /*** Odd functions **/
7088 IWineD3DDeviceImpl_Init3D
,
7089 IWineD3DDeviceImpl_Uninit3D
,
7090 IWineD3DDeviceImpl_SetFullscreen
,
7091 IWineD3DDeviceImpl_SetMultithreaded
,
7092 IWineD3DDeviceImpl_EvictManagedResources
,
7093 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7094 IWineD3DDeviceImpl_GetBackBuffer
,
7095 IWineD3DDeviceImpl_GetCreationParameters
,
7096 IWineD3DDeviceImpl_GetDeviceCaps
,
7097 IWineD3DDeviceImpl_GetDirect3D
,
7098 IWineD3DDeviceImpl_GetDisplayMode
,
7099 IWineD3DDeviceImpl_SetDisplayMode
,
7100 IWineD3DDeviceImpl_GetHWND
,
7101 IWineD3DDeviceImpl_SetHWND
,
7102 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7103 IWineD3DDeviceImpl_GetRasterStatus
,
7104 IWineD3DDeviceImpl_GetSwapChain
,
7105 IWineD3DDeviceImpl_Reset
,
7106 IWineD3DDeviceImpl_SetDialogBoxMode
,
7107 IWineD3DDeviceImpl_SetCursorProperties
,
7108 IWineD3DDeviceImpl_SetCursorPosition
,
7109 IWineD3DDeviceImpl_ShowCursor
,
7110 IWineD3DDeviceImpl_TestCooperativeLevel
,
7111 /*** Getters and setters **/
7112 IWineD3DDeviceImpl_SetClipPlane
,
7113 IWineD3DDeviceImpl_GetClipPlane
,
7114 IWineD3DDeviceImpl_SetClipStatus
,
7115 IWineD3DDeviceImpl_GetClipStatus
,
7116 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7117 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7118 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7119 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7120 IWineD3DDeviceImpl_SetFVF
,
7121 IWineD3DDeviceImpl_GetFVF
,
7122 IWineD3DDeviceImpl_SetGammaRamp
,
7123 IWineD3DDeviceImpl_GetGammaRamp
,
7124 IWineD3DDeviceImpl_SetIndices
,
7125 IWineD3DDeviceImpl_GetIndices
,
7126 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7127 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7128 IWineD3DDeviceImpl_SetLight
,
7129 IWineD3DDeviceImpl_GetLight
,
7130 IWineD3DDeviceImpl_SetLightEnable
,
7131 IWineD3DDeviceImpl_GetLightEnable
,
7132 IWineD3DDeviceImpl_SetMaterial
,
7133 IWineD3DDeviceImpl_GetMaterial
,
7134 IWineD3DDeviceImpl_SetNPatchMode
,
7135 IWineD3DDeviceImpl_GetNPatchMode
,
7136 IWineD3DDeviceImpl_SetPaletteEntries
,
7137 IWineD3DDeviceImpl_GetPaletteEntries
,
7138 IWineD3DDeviceImpl_SetPixelShader
,
7139 IWineD3DDeviceImpl_GetPixelShader
,
7140 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7141 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7142 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7143 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7144 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7145 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7146 IWineD3DDeviceImpl_SetRenderState
,
7147 IWineD3DDeviceImpl_GetRenderState
,
7148 IWineD3DDeviceImpl_SetRenderTarget
,
7149 IWineD3DDeviceImpl_GetRenderTarget
,
7150 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7151 IWineD3DDeviceImpl_SetSamplerState
,
7152 IWineD3DDeviceImpl_GetSamplerState
,
7153 IWineD3DDeviceImpl_SetScissorRect
,
7154 IWineD3DDeviceImpl_GetScissorRect
,
7155 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7156 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7157 IWineD3DDeviceImpl_SetStreamSource
,
7158 IWineD3DDeviceImpl_GetStreamSource
,
7159 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7160 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7161 IWineD3DDeviceImpl_SetTexture
,
7162 IWineD3DDeviceImpl_GetTexture
,
7163 IWineD3DDeviceImpl_SetTextureStageState
,
7164 IWineD3DDeviceImpl_GetTextureStageState
,
7165 IWineD3DDeviceImpl_SetTransform
,
7166 IWineD3DDeviceImpl_GetTransform
,
7167 IWineD3DDeviceImpl_SetVertexDeclaration
,
7168 IWineD3DDeviceImpl_GetVertexDeclaration
,
7169 IWineD3DDeviceImpl_SetVertexShader
,
7170 IWineD3DDeviceImpl_GetVertexShader
,
7171 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7172 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7173 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7174 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7175 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7176 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7177 IWineD3DDeviceImpl_SetViewport
,
7178 IWineD3DDeviceImpl_GetViewport
,
7179 IWineD3DDeviceImpl_MultiplyTransform
,
7180 IWineD3DDeviceImpl_ValidateDevice
,
7181 IWineD3DDeviceImpl_ProcessVertices
,
7182 /*** State block ***/
7183 IWineD3DDeviceImpl_BeginStateBlock
,
7184 IWineD3DDeviceImpl_EndStateBlock
,
7185 /*** Scene management ***/
7186 IWineD3DDeviceImpl_BeginScene
,
7187 IWineD3DDeviceImpl_EndScene
,
7188 IWineD3DDeviceImpl_Present
,
7189 IWineD3DDeviceImpl_Clear
,
7191 IWineD3DDeviceImpl_DrawPrimitive
,
7192 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7193 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7194 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7195 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7196 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7197 IWineD3DDeviceImpl_DrawRectPatch
,
7198 IWineD3DDeviceImpl_DrawTriPatch
,
7199 IWineD3DDeviceImpl_DeletePatch
,
7200 IWineD3DDeviceImpl_ColorFill
,
7201 IWineD3DDeviceImpl_UpdateTexture
,
7202 IWineD3DDeviceImpl_UpdateSurface
,
7203 IWineD3DDeviceImpl_GetFrontBufferData
,
7204 /*** object tracking ***/
7205 IWineD3DDeviceImpl_ResourceReleased
7209 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7210 WINED3DRS_ALPHABLENDENABLE
,
7211 WINED3DRS_ALPHAFUNC
,
7212 WINED3DRS_ALPHAREF
,
7213 WINED3DRS_ALPHATESTENABLE
,
7215 WINED3DRS_COLORWRITEENABLE
,
7216 WINED3DRS_DESTBLEND
,
7217 WINED3DRS_DITHERENABLE
,
7218 WINED3DRS_FILLMODE
,
7219 WINED3DRS_FOGDENSITY
,
7221 WINED3DRS_FOGSTART
,
7222 WINED3DRS_LASTPIXEL
,
7223 WINED3DRS_SHADEMODE
,
7224 WINED3DRS_SRCBLEND
,
7225 WINED3DRS_STENCILENABLE
,
7226 WINED3DRS_STENCILFAIL
,
7227 WINED3DRS_STENCILFUNC
,
7228 WINED3DRS_STENCILMASK
,
7229 WINED3DRS_STENCILPASS
,
7230 WINED3DRS_STENCILREF
,
7231 WINED3DRS_STENCILWRITEMASK
,
7232 WINED3DRS_STENCILZFAIL
,
7233 WINED3DRS_TEXTUREFACTOR
,
7244 WINED3DRS_ZWRITEENABLE
7247 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7248 WINED3DTSS_ADDRESSW
,
7249 WINED3DTSS_ALPHAARG0
,
7250 WINED3DTSS_ALPHAARG1
,
7251 WINED3DTSS_ALPHAARG2
,
7252 WINED3DTSS_ALPHAOP
,
7253 WINED3DTSS_BUMPENVLOFFSET
,
7254 WINED3DTSS_BUMPENVLSCALE
,
7255 WINED3DTSS_BUMPENVMAT00
,
7256 WINED3DTSS_BUMPENVMAT01
,
7257 WINED3DTSS_BUMPENVMAT10
,
7258 WINED3DTSS_BUMPENVMAT11
,
7259 WINED3DTSS_COLORARG0
,
7260 WINED3DTSS_COLORARG1
,
7261 WINED3DTSS_COLORARG2
,
7262 WINED3DTSS_COLOROP
,
7263 WINED3DTSS_RESULTARG
,
7264 WINED3DTSS_TEXCOORDINDEX
,
7265 WINED3DTSS_TEXTURETRANSFORMFLAGS
7268 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7269 WINED3DSAMP_ADDRESSU
,
7270 WINED3DSAMP_ADDRESSV
,
7271 WINED3DSAMP_ADDRESSW
,
7272 WINED3DSAMP_BORDERCOLOR
,
7273 WINED3DSAMP_MAGFILTER
,
7274 WINED3DSAMP_MINFILTER
,
7275 WINED3DSAMP_MIPFILTER
,
7276 WINED3DSAMP_MIPMAPLODBIAS
,
7277 WINED3DSAMP_MAXMIPLEVEL
,
7278 WINED3DSAMP_MAXANISOTROPY
,
7279 WINED3DSAMP_SRGBTEXTURE
,
7280 WINED3DSAMP_ELEMENTINDEX
7283 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7285 WINED3DRS_AMBIENTMATERIALSOURCE
,
7286 WINED3DRS_CLIPPING
,
7287 WINED3DRS_CLIPPLANEENABLE
,
7288 WINED3DRS_COLORVERTEX
,
7289 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7290 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7291 WINED3DRS_FOGDENSITY
,
7293 WINED3DRS_FOGSTART
,
7294 WINED3DRS_FOGTABLEMODE
,
7295 WINED3DRS_FOGVERTEXMODE
,
7296 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7297 WINED3DRS_LIGHTING
,
7298 WINED3DRS_LOCALVIEWER
,
7299 WINED3DRS_MULTISAMPLEANTIALIAS
,
7300 WINED3DRS_MULTISAMPLEMASK
,
7301 WINED3DRS_NORMALIZENORMALS
,
7302 WINED3DRS_PATCHEDGESTYLE
,
7303 WINED3DRS_POINTSCALE_A
,
7304 WINED3DRS_POINTSCALE_B
,
7305 WINED3DRS_POINTSCALE_C
,
7306 WINED3DRS_POINTSCALEENABLE
,
7307 WINED3DRS_POINTSIZE
,
7308 WINED3DRS_POINTSIZE_MAX
,
7309 WINED3DRS_POINTSIZE_MIN
,
7310 WINED3DRS_POINTSPRITEENABLE
,
7311 WINED3DRS_RANGEFOGENABLE
,
7312 WINED3DRS_SPECULARMATERIALSOURCE
,
7313 WINED3DRS_TWEENFACTOR
,
7314 WINED3DRS_VERTEXBLEND
,
7315 WINED3DRS_CULLMODE
,
7319 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7320 WINED3DTSS_TEXCOORDINDEX
,
7321 WINED3DTSS_TEXTURETRANSFORMFLAGS
7324 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7325 WINED3DSAMP_DMAPOFFSET
7328 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7329 DWORD rep
= StateTable
[state
].representative
;
7333 WineD3DContext
*context
;
7336 for(i
= 0; i
< This
->numContexts
; i
++) {
7337 context
= This
->contexts
[i
];
7338 if(isStateDirty(context
, rep
)) continue;
7340 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7343 context
->isStateDirty
[idx
] |= (1 << shift
);