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
);
280 object
->vbo_size
= object
->resource
.size
;
281 object
->vbo_usage
= glUsage
;
287 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
288 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
289 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
291 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
296 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
297 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
299 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
300 IWineD3DVertexBufferImpl
*object
;
301 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
302 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
306 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
307 *ppVertexBuffer
= NULL
;
308 return WINED3DERR_INVALIDCALL
;
309 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
310 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
311 * anyway, SCRATCH vertex buffers aren't useable anywhere
313 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
314 *ppVertexBuffer
= NULL
;
315 return WINED3DERR_INVALIDCALL
;
318 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
320 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
321 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
325 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
326 * drawStridedFast (half-life 2).
328 * Basically converting the vertices in the buffer is quite expensive, and observations
329 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
330 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
332 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
333 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
334 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
335 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
337 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
338 * more. In this call we can convert dx7 buffers too.
340 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
341 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
342 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
343 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
344 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
345 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
346 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
347 } else if(dxVersion
<= 7 && conv
) {
348 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
355 static void CreateIndexBufferVBO(IWineD3DDeviceImpl
*This
, IWineD3DIndexBufferImpl
*object
) {
356 GLenum error
, glUsage
;
357 TRACE("Creating VBO for Index Buffer %p\n", object
);
359 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
360 * restored on the next draw
362 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
364 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
365 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
370 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
371 error
= glGetError();
372 if(error
!= GL_NO_ERROR
|| object
->vbo
== 0) {
373 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
377 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->vbo
));
378 error
= glGetError();
379 if(error
!= GL_NO_ERROR
) {
380 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error
), error
);
384 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
385 * copy no readback will be needed
387 glUsage
= GL_STATIC_DRAW_ARB
;
388 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
389 error
= glGetError();
390 if(error
!= GL_NO_ERROR
) {
391 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error
), error
);
395 TRACE("Successfully created vbo %d for index buffer %p\n", object
->vbo
, object
);
399 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0));
400 GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
405 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
406 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
407 HANDLE
*sharedHandle
, IUnknown
*parent
) {
408 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
409 IWineD3DIndexBufferImpl
*object
;
410 TRACE("(%p) Creating index buffer\n", This
);
412 /* Allocate the storage for the device */
413 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
415 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
416 CreateIndexBufferVBO(This
, object
);
419 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
420 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
421 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
426 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
428 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
429 IWineD3DStateBlockImpl
*object
;
433 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
434 object
->blockType
= Type
;
436 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
437 list_init(&object
->lightMap
[i
]);
440 /* Special case - Used during initialization to produce a placeholder stateblock
441 so other functions called can update a state block */
442 if (Type
== WINED3DSBT_INIT
) {
443 /* Don't bother increasing the reference count otherwise a device will never
444 be freed due to circular dependencies */
448 temp_result
= allocate_shader_constants(object
);
449 if (WINED3D_OK
!= temp_result
)
452 /* Otherwise, might as well set the whole state block to the appropriate values */
453 if (This
->stateBlock
!= NULL
)
454 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
456 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
458 /* Reset the ref and type after kludging it */
459 object
->wineD3DDevice
= This
;
461 object
->blockType
= Type
;
463 TRACE("Updating changed flags appropriate for type %d\n", Type
);
465 if (Type
== WINED3DSBT_ALL
) {
467 TRACE("ALL => Pretend everything has changed\n");
468 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
470 /* Lights are not part of the changed / set structure */
471 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
473 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
474 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
475 light
->changed
= TRUE
;
476 light
->enabledChanged
= TRUE
;
479 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
480 object
->contained_render_states
[j
- 1] = j
;
482 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
483 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
484 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
485 object
->contained_transform_states
[j
- 1] = j
;
487 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
488 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
489 object
->contained_vs_consts_f
[j
] = j
;
491 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
492 for(j
= 0; j
< MAX_CONST_I
; j
++) {
493 object
->contained_vs_consts_i
[j
] = j
;
495 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
496 for(j
= 0; j
< MAX_CONST_B
; j
++) {
497 object
->contained_vs_consts_b
[j
] = j
;
499 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
500 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
501 object
->contained_ps_consts_f
[j
] = j
;
503 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
504 for(j
= 0; j
< MAX_CONST_I
; j
++) {
505 object
->contained_ps_consts_i
[j
] = j
;
507 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
508 for(j
= 0; j
< MAX_CONST_B
; j
++) {
509 object
->contained_ps_consts_b
[j
] = j
;
511 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
512 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
513 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
514 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
515 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
516 object
->num_contained_tss_states
++;
519 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
520 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
521 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
522 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
523 object
->num_contained_sampler_states
++;
527 for(i
= 0; i
< MAX_STREAMS
; i
++) {
528 if(object
->streamSource
[i
]) {
529 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
532 if(object
->pIndexData
) {
533 IWineD3DIndexBuffer_AddRef(object
->pIndexData
);
535 if(object
->vertexShader
) {
536 IWineD3DVertexShader_AddRef(object
->vertexShader
);
538 if(object
->pixelShader
) {
539 IWineD3DPixelShader_AddRef(object
->pixelShader
);
542 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
544 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
545 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
547 object
->changed
.pixelShader
= TRUE
;
549 /* Pixel Shader Constants */
550 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
551 object
->contained_ps_consts_f
[i
] = i
;
552 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
554 object
->num_contained_ps_consts_f
= GL_LIMITS(vshader_constantsF
);
555 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
556 object
->contained_ps_consts_b
[i
] = i
;
557 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
559 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
560 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
561 object
->contained_ps_consts_i
[i
] = i
;
562 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
564 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
566 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
567 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
568 object
->contained_render_states
[i
] = SavedPixelStates_R
[i
];
570 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
571 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
572 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
573 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
574 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
575 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedPixelStates_T
[i
];
576 object
->num_contained_tss_states
++;
579 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
580 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
581 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
582 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
583 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedPixelStates_S
[i
];
584 object
->num_contained_sampler_states
++;
587 if(object
->pixelShader
) {
588 IWineD3DPixelShader_AddRef(object
->pixelShader
);
591 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
592 * on them. This makes releasing the buffer easier
594 for(i
= 0; i
< MAX_STREAMS
; i
++) {
595 object
->streamSource
[i
] = NULL
;
597 object
->pIndexData
= NULL
;
598 object
->vertexShader
= NULL
;
600 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
602 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
603 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
605 object
->changed
.vertexShader
= TRUE
;
607 /* Vertex Shader Constants */
608 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
609 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
610 object
->contained_vs_consts_f
[i
] = i
;
612 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
613 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
614 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
615 object
->contained_vs_consts_b
[i
] = i
;
617 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
618 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
619 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
620 object
->contained_vs_consts_i
[i
] = i
;
622 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
623 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
624 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
625 object
->contained_render_states
[i
] = SavedVertexStates_R
[i
];
627 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
628 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
629 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
630 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
631 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
632 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= SavedVertexStates_T
[i
];
633 object
->num_contained_tss_states
++;
636 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
637 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
638 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
639 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
640 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= SavedVertexStates_S
[i
];
641 object
->num_contained_sampler_states
++;
645 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
647 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
648 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
649 light
->changed
= TRUE
;
650 light
->enabledChanged
= TRUE
;
654 for(i
= 0; i
< MAX_STREAMS
; i
++) {
655 if(object
->streamSource
[i
]) {
656 IWineD3DVertexBuffer_AddRef(object
->streamSource
[i
]);
659 if(object
->vertexShader
) {
660 IWineD3DVertexShader_AddRef(object
->vertexShader
);
662 object
->pIndexData
= NULL
;
663 object
->pixelShader
= NULL
;
665 FIXME("Unrecognized state block type %d\n", Type
);
668 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
672 /* ************************************
674 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
677 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
679 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.
681 ******************************** */
683 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
) {
684 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
685 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
686 unsigned int Size
= 1;
687 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
, NULL
, NULL
);
688 TRACE("(%p) Create surface\n",This
);
690 /** FIXME: Check ranges on the inputs are valid
693 * [in] Quality level. The valid range is between zero and one less than the level
694 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
695 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
696 * values of paired render targets, depth stencil surfaces, and the MultiSample type
698 *******************************/
703 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
705 * If this flag is set, the contents of the depth stencil buffer will be
706 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
707 * with a different depth surface.
709 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
710 ***************************/
712 if(MultisampleQuality
< 0) {
713 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
714 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
717 if(MultisampleQuality
> 0) {
718 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
719 MultisampleQuality
=0;
722 /** FIXME: Check that the format is supported
724 *******************************/
726 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
727 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
729 *********************************/
730 if (WINED3DFMT_UNKNOWN
== Format
) {
732 } else if (Format
== WINED3DFMT_DXT1
) {
733 /* DXT1 is half byte per pixel */
734 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
736 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
737 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
738 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
740 /* The pitch is a multiple of 4 bytes */
741 Size
= ((Width
* tableEntry
->bpp
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
745 /** Create and initialise the surface resource **/
746 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
747 /* "Standalone" surface */
748 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
750 object
->currentDesc
.Width
= Width
;
751 object
->currentDesc
.Height
= Height
;
752 object
->currentDesc
.MultiSampleType
= MultiSample
;
753 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
754 object
->glDescription
.level
= Level
;
758 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
759 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
760 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
763 if (WINED3DFMT_UNKNOWN
!= Format
) {
764 object
->bytesPerPixel
= tableEntry
->bpp
;
766 object
->bytesPerPixel
= 0;
769 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
771 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
773 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
774 * this function is too deep to need to care about things like this.
775 * Levels need to be checked too, and possibly Type since they all affect what can be done.
776 * ****************************************/
778 case WINED3DPOOL_SCRATCH
:
780 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
781 "which are mutually exclusive, setting lockable to TRUE\n");
784 case WINED3DPOOL_SYSTEMMEM
:
785 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
786 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
787 case WINED3DPOOL_MANAGED
:
788 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
789 "Usage of DYNAMIC which are mutually exclusive, not doing "
790 "anything just telling you.\n");
792 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
793 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
794 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
795 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
798 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
802 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
803 FIXME("Trying to create a render target that isn't in the default pool\n");
806 /* mark the texture as dirty so that it gets loaded first time around*/
807 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
808 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
809 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
810 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
812 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
813 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
814 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
816 /* Look at the implementation and set the correct Vtable */
819 /* Check if a 3D adapter is available when creating gl surfaces */
821 ERR("OpenGL surfaces are not available without opengl\n");
822 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
823 HeapFree(GetProcessHeap(), 0, object
);
824 return WINED3DERR_NOTAVAILABLE
;
829 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
833 /* To be sure to catch this */
834 ERR("Unknown requested surface implementation %d!\n", Impl
);
835 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
836 return WINED3DERR_INVALIDCALL
;
839 list_init(&object
->renderbuffers
);
841 /* Call the private setup routine */
842 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
846 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
847 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
848 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
849 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
851 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
852 IWineD3DTextureImpl
*object
;
857 unsigned int pow2Width
;
858 unsigned int pow2Height
;
859 const GlPixelFormatDesc
*glDesc
;
860 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
863 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
864 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
865 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
867 /* TODO: It should only be possible to create textures for formats
868 that are reported as supported */
869 if (WINED3DFMT_UNKNOWN
>= Format
) {
870 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
871 return WINED3DERR_INVALIDCALL
;
874 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
875 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
876 object
->width
= Width
;
877 object
->height
= Height
;
879 /** Non-power2 support **/
880 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
884 /* Find the nearest pow2 match */
885 pow2Width
= pow2Height
= 1;
886 while (pow2Width
< Width
) pow2Width
<<= 1;
887 while (pow2Height
< Height
) pow2Height
<<= 1;
889 if(pow2Width
!= Width
|| pow2Height
!= Height
) {
891 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
892 HeapFree(GetProcessHeap(), 0, object
);
894 return WINED3DERR_INVALIDCALL
;
901 /** FIXME: add support for real non-power-two if it's provided by the video card **/
902 /* Precalculated scaling for 'faked' non power of two texture coords */
903 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
904 (Width
!= pow2Width
|| Height
!= pow2Height
)) {
905 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
906 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
907 object
->baseTexture
.pow2Matrix
[10] = 1.0;
908 object
->baseTexture
.pow2Matrix
[15] = 1.0;
909 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
911 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
912 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
913 object
->baseTexture
.pow2Matrix
[10] = 1.0;
914 object
->baseTexture
.pow2Matrix
[15] = 1.0;
915 object
->target
= GL_TEXTURE_2D
;
917 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
919 /* Calculate levels for mip mapping */
920 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
921 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
922 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
923 return WINED3DERR_INVALIDCALL
;
926 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
927 return WINED3DERR_INVALIDCALL
;
929 object
->baseTexture
.levels
= 1;
930 } else if (Levels
== 0) {
931 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
932 object
->baseTexture
.levels
++;
935 while (tmpW
> 1 || tmpH
> 1) {
936 tmpW
= max(1, tmpW
>> 1);
937 tmpH
= max(1, tmpH
>> 1);
938 object
->baseTexture
.levels
++;
940 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
943 /* Generate all the surfaces */
946 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
948 /* use the callback to create the texture surface */
949 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
],NULL
);
950 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
951 FIXME("Failed to create surface %p\n", object
);
953 object
->surfaces
[i
] = NULL
;
954 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
960 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
961 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
962 /* calculate the next mipmap level */
963 tmpW
= max(1, tmpW
>> 1);
964 tmpH
= max(1, tmpH
>> 1);
966 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
968 TRACE("(%p) : Created texture %p\n", This
, object
);
972 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
973 UINT Width
, UINT Height
, UINT Depth
,
974 UINT Levels
, DWORD Usage
,
975 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
976 IWineD3DVolumeTexture
**ppVolumeTexture
,
977 HANDLE
*pSharedHandle
, IUnknown
*parent
,
978 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
980 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
981 IWineD3DVolumeTextureImpl
*object
;
986 const GlPixelFormatDesc
*glDesc
;
988 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
990 /* TODO: It should only be possible to create textures for formats
991 that are reported as supported */
992 if (WINED3DFMT_UNKNOWN
>= Format
) {
993 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
994 return WINED3DERR_INVALIDCALL
;
996 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
997 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
998 return WINED3DERR_INVALIDCALL
;
1001 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
1002 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1004 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1005 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1007 object
->width
= Width
;
1008 object
->height
= Height
;
1009 object
->depth
= Depth
;
1011 /* Is NP2 support for volumes needed? */
1012 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
1013 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
1014 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1015 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1017 /* Calculate levels for mip mapping */
1018 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1019 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1020 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1021 return WINED3DERR_INVALIDCALL
;
1024 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1025 return WINED3DERR_INVALIDCALL
;
1028 } else if (Levels
== 0) {
1029 object
->baseTexture
.levels
++;
1033 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
1034 tmpW
= max(1, tmpW
>> 1);
1035 tmpH
= max(1, tmpH
>> 1);
1036 tmpD
= max(1, tmpD
>> 1);
1037 object
->baseTexture
.levels
++;
1039 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1042 /* Generate all the surfaces */
1047 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1050 /* Create the volume */
1051 hr
= D3DCB_CreateVolume(This
->parent
, parent
, tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
,
1052 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
1055 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
1056 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
1057 *ppVolumeTexture
= NULL
;
1061 /* Set its container to this object */
1062 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1064 /* calcualte the next mipmap level */
1065 tmpW
= max(1, tmpW
>> 1);
1066 tmpH
= max(1, tmpH
>> 1);
1067 tmpD
= max(1, tmpD
>> 1);
1069 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1071 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1072 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1076 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1077 UINT Width
, UINT Height
, UINT Depth
,
1079 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1080 IWineD3DVolume
** ppVolume
,
1081 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1083 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1084 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1085 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
, NULL
, NULL
);
1087 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1088 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1089 return WINED3DERR_INVALIDCALL
;
1092 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1094 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1095 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1097 object
->currentDesc
.Width
= Width
;
1098 object
->currentDesc
.Height
= Height
;
1099 object
->currentDesc
.Depth
= Depth
;
1100 object
->bytesPerPixel
= formatDesc
->bpp
;
1102 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1103 object
->lockable
= TRUE
;
1104 object
->locked
= FALSE
;
1105 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1106 object
->dirty
= TRUE
;
1108 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1111 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1112 UINT Levels
, DWORD Usage
,
1113 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1114 IWineD3DCubeTexture
**ppCubeTexture
,
1115 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1116 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1118 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1119 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1123 unsigned int pow2EdgeLength
= EdgeLength
;
1124 const GlPixelFormatDesc
*glDesc
;
1125 getFormatDescEntry(Format
, &GLINFO_LOCATION
, &glDesc
);
1127 /* TODO: It should only be possible to create textures for formats
1128 that are reported as supported */
1129 if (WINED3DFMT_UNKNOWN
>= Format
) {
1130 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1131 return WINED3DERR_INVALIDCALL
;
1134 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1135 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1136 return WINED3DERR_INVALIDCALL
;
1139 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1140 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1142 TRACE("(%p) Create Cube Texture\n", This
);
1144 /** Non-power2 support **/
1146 /* Find the nearest pow2 match */
1148 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1150 object
->edgeLength
= EdgeLength
;
1151 /* TODO: support for native non-power 2 */
1152 /* Precalculated scaling for 'faked' non power of two texture coords */
1153 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1154 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1155 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1156 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1158 /* Calculate levels for mip mapping */
1159 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
) {
1160 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP
)) {
1161 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1162 HeapFree(GetProcessHeap(), 0, object
);
1163 *ppCubeTexture
= NULL
;
1165 return WINED3DERR_INVALIDCALL
;
1168 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1169 HeapFree(GetProcessHeap(), 0, object
);
1170 *ppCubeTexture
= NULL
;
1172 return WINED3DERR_INVALIDCALL
;
1175 } else if (Levels
== 0) {
1176 object
->baseTexture
.levels
++;
1179 tmpW
= max(1, tmpW
>> 1);
1180 object
->baseTexture
.levels
++;
1182 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1185 /* Generate all the surfaces */
1187 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1189 /* Create the 6 faces */
1190 for (j
= 0; j
< 6; j
++) {
1192 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1193 i
/* Level */, j
, &object
->surfaces
[j
][i
],pSharedHandle
);
1195 if(hr
!= WINED3D_OK
) {
1199 for (l
= 0; l
< j
; l
++) {
1200 IWineD3DSurface_Release(object
->surfaces
[l
][i
]);
1202 for (k
= 0; k
< i
; k
++) {
1203 for (l
= 0; l
< 6; l
++) {
1204 IWineD3DSurface_Release(object
->surfaces
[l
][k
]);
1208 FIXME("(%p) Failed to create surface\n",object
);
1209 HeapFree(GetProcessHeap(),0,object
);
1210 *ppCubeTexture
= NULL
;
1213 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1214 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1216 tmpW
= max(1, tmpW
>> 1);
1218 object
->baseTexture
.shader_conversion_group
= glDesc
->conversion_group
;
1220 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1221 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1225 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1226 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1227 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1228 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1230 /* Just a check to see if we support this type of query */
1232 case WINED3DQUERYTYPE_OCCLUSION
:
1233 TRACE("(%p) occlusion query\n", This
);
1234 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1237 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1240 case WINED3DQUERYTYPE_EVENT
:
1241 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1242 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1243 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1245 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1250 case WINED3DQUERYTYPE_VCACHE
:
1251 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1252 case WINED3DQUERYTYPE_VERTEXSTATS
:
1253 case WINED3DQUERYTYPE_TIMESTAMP
:
1254 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1255 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1256 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1257 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1258 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1259 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1260 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1261 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1263 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1265 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1269 D3DCREATEOBJECTINSTANCE(object
, Query
)
1270 object
->type
= Type
;
1271 object
->state
= QUERY_CREATED
;
1272 /* allocated the 'extended' data based on the type of query requested */
1274 case WINED3DQUERYTYPE_OCCLUSION
:
1275 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1276 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1278 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1279 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1280 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1283 case WINED3DQUERYTYPE_EVENT
:
1284 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1285 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1287 if(GL_SUPPORT(APPLE_FENCE
)) {
1288 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1289 checkGLcall("glGenFencesAPPLE");
1290 } else if(GL_SUPPORT(NV_FENCE
)) {
1291 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1292 checkGLcall("glGenFencesNV");
1296 case WINED3DQUERYTYPE_VCACHE
:
1297 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1298 case WINED3DQUERYTYPE_VERTEXSTATS
:
1299 case WINED3DQUERYTYPE_TIMESTAMP
:
1300 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1301 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1302 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1303 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1304 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1305 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1306 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1307 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1309 object
->extendedData
= 0;
1310 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1312 TRACE("(%p) : Created Query %p\n", This
, object
);
1316 /*****************************************************************************
1317 * IWineD3DDeviceImpl_SetupFullscreenWindow
1319 * Helper function that modifies a HWND's Style and ExStyle for proper
1323 * iface: Pointer to the IWineD3DDevice interface
1324 * window: Window to setup
1326 *****************************************************************************/
1327 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1330 LONG style
, exStyle
;
1331 /* Don't do anything if an original style is stored.
1332 * That shouldn't happen
1334 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1335 if (This
->style
|| This
->exStyle
) {
1336 ERR("(%p): Want to change the window parameters of HWND %p, but "
1337 "another style is stored for restoration afterwards\n", This
, window
);
1340 /* Get the parameters and save them */
1341 style
= GetWindowLongW(window
, GWL_STYLE
);
1342 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1343 This
->style
= style
;
1344 This
->exStyle
= exStyle
;
1346 /* Filter out window decorations */
1347 style
&= ~WS_CAPTION
;
1348 style
&= ~WS_THICKFRAME
;
1349 exStyle
&= ~WS_EX_WINDOWEDGE
;
1350 exStyle
&= ~WS_EX_CLIENTEDGE
;
1352 /* Make sure the window is managed, otherwise we won't get keyboard input */
1353 style
|= WS_POPUP
| WS_SYSMENU
;
1355 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1356 This
->style
, This
->exStyle
, style
, exStyle
);
1358 SetWindowLongW(window
, GWL_STYLE
, style
);
1359 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1361 /* Inform the window about the update. */
1362 SetWindowPos(window
, HWND_TOP
, 0, 0,
1363 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1364 ShowWindow(window
, SW_NORMAL
);
1367 /*****************************************************************************
1368 * IWineD3DDeviceImpl_RestoreWindow
1370 * Helper function that restores a windows' properties when taking it out
1371 * of fullscreen mode
1374 * iface: Pointer to the IWineD3DDevice interface
1375 * window: Window to setup
1377 *****************************************************************************/
1378 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1379 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1381 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1382 * switch, do nothing
1384 if (!This
->style
&& !This
->exStyle
) return;
1386 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1387 This
, window
, This
->style
, This
->exStyle
);
1389 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1390 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1392 /* Delete the old values */
1396 /* Inform the window about the update */
1397 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1398 0, 0, 0, 0, /* Pos, Size, ignored */
1399 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1402 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1403 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1405 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1406 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1407 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1410 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1411 HRESULT hr
= WINED3D_OK
;
1412 IUnknown
*bufferParent
;
1413 BOOL displaymode_set
= FALSE
;
1414 WINED3DDISPLAYMODE Mode
;
1415 const StaticPixelFormatDesc
*formatDesc
;
1417 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1419 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1420 * does a device hold a reference to a swap chain giving them a lifetime of the device
1421 * or does the swap chain notify the device of its destruction.
1422 *******************************/
1424 /* Check the params */
1425 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1426 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1427 return WINED3DERR_INVALIDCALL
;
1428 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1429 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");
1432 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1434 /*********************
1435 * Lookup the window Handle and the relating X window handle
1436 ********************/
1438 /* Setup hwnd we are using, plus which display this equates to */
1439 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1440 if (!object
->win_handle
) {
1441 object
->win_handle
= This
->createParms
.hFocusWindow
;
1443 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, object
->win_handle
);
1445 hDc
= GetDC(object
->win_handle
);
1446 TRACE("Using hDc %p\n", hDc
);
1449 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1450 return WINED3DERR_NOTAVAILABLE
;
1453 /* Get info on the current display setup */
1454 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1455 object
->orig_width
= Mode
.Width
;
1456 object
->orig_height
= Mode
.Height
;
1457 object
->orig_fmt
= Mode
.Format
;
1458 formatDesc
= getFormatDescEntry(Mode
.Format
, NULL
, NULL
);
1460 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1461 * then the corresponding dimension of the client area of the hDeviceWindow
1462 * (or the focus window, if hDeviceWindow is NULL) is taken.
1463 **********************/
1465 if (pPresentationParameters
->Windowed
&&
1466 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1467 (pPresentationParameters
->BackBufferHeight
== 0) ||
1468 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1471 GetClientRect(object
->win_handle
, &Rect
);
1473 if (pPresentationParameters
->BackBufferWidth
== 0) {
1474 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1475 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1477 if (pPresentationParameters
->BackBufferHeight
== 0) {
1478 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1479 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1481 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1482 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1483 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1487 /* Put the correct figures in the presentation parameters */
1488 TRACE("Copying across presentation parameters\n");
1489 object
->presentParms
= *pPresentationParameters
;
1491 TRACE("calling rendertarget CB\n");
1492 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1494 object
->presentParms
.BackBufferWidth
,
1495 object
->presentParms
.BackBufferHeight
,
1496 object
->presentParms
.BackBufferFormat
,
1497 object
->presentParms
.MultiSampleType
,
1498 object
->presentParms
.MultiSampleQuality
,
1499 TRUE
/* Lockable */,
1500 &object
->frontBuffer
,
1501 NULL
/* pShared (always null)*/);
1502 if (object
->frontBuffer
!= NULL
) {
1503 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1504 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1506 ERR("Failed to create the front buffer\n");
1510 /*********************
1511 * Windowed / Fullscreen
1512 *******************/
1515 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1516 * so we should really check to see if there is a fullscreen swapchain already
1517 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1518 **************************************/
1520 if (!pPresentationParameters
->Windowed
) {
1521 WINED3DDISPLAYMODE mode
;
1524 /* Change the display settings */
1525 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1526 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1527 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1528 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1530 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1531 displaymode_set
= TRUE
;
1532 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1536 * Create an opengl context for the display visual
1537 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1538 * use different properties after that point in time. FIXME: How to handle when requested format
1539 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1540 * it chooses is identical to the one already being used!
1541 **********************************/
1542 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1544 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1545 if(!object
->context
)
1546 return E_OUTOFMEMORY
;
1547 object
->num_contexts
= 1;
1549 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1550 if (!object
->context
[0]) {
1551 ERR("Failed to create a new context\n");
1552 hr
= WINED3DERR_NOTAVAILABLE
;
1555 TRACE("Context created (HWND=%p, glContext=%p)\n",
1556 object
->win_handle
, object
->context
[0]->glCtx
);
1559 /*********************
1560 * Create the back, front and stencil buffers
1561 *******************/
1562 if(object
->presentParms
.BackBufferCount
> 0) {
1565 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1566 if(!object
->backBuffer
) {
1567 ERR("Out of memory\n");
1572 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1573 TRACE("calling rendertarget CB\n");
1574 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1576 object
->presentParms
.BackBufferWidth
,
1577 object
->presentParms
.BackBufferHeight
,
1578 object
->presentParms
.BackBufferFormat
,
1579 object
->presentParms
.MultiSampleType
,
1580 object
->presentParms
.MultiSampleQuality
,
1581 TRUE
/* Lockable */,
1582 &object
->backBuffer
[i
],
1583 NULL
/* pShared (always null)*/);
1584 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1585 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1587 ERR("Cannot create new back buffer\n");
1591 glDrawBuffer(GL_BACK
);
1592 checkGLcall("glDrawBuffer(GL_BACK)");
1596 object
->backBuffer
= NULL
;
1598 /* Single buffering - draw to front buffer */
1600 glDrawBuffer(GL_FRONT
);
1601 checkGLcall("glDrawBuffer(GL_FRONT)");
1605 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1606 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1607 TRACE("Creating depth stencil buffer\n");
1608 if (This
->auto_depth_stencil_buffer
== NULL
) {
1609 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1611 object
->presentParms
.BackBufferWidth
,
1612 object
->presentParms
.BackBufferHeight
,
1613 object
->presentParms
.AutoDepthStencilFormat
,
1614 object
->presentParms
.MultiSampleType
,
1615 object
->presentParms
.MultiSampleQuality
,
1616 FALSE
/* FIXME: Discard */,
1617 &This
->auto_depth_stencil_buffer
,
1618 NULL
/* pShared (always null)*/ );
1619 if (This
->auto_depth_stencil_buffer
!= NULL
)
1620 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1623 /** TODO: A check on width, height and multisample types
1624 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1625 ****************************/
1626 object
->wantsDepthStencilBuffer
= TRUE
;
1628 object
->wantsDepthStencilBuffer
= FALSE
;
1631 TRACE("Created swapchain %p\n", object
);
1632 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1636 if (displaymode_set
) {
1640 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1643 /* Change the display settings */
1644 memset(&devmode
, 0, sizeof(devmode
));
1645 devmode
.dmSize
= sizeof(devmode
);
1646 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1647 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1648 devmode
.dmPelsWidth
= object
->orig_width
;
1649 devmode
.dmPelsHeight
= object
->orig_height
;
1650 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1653 if (object
->backBuffer
) {
1655 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1656 if(object
->backBuffer
[i
]) {
1657 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1658 IUnknown_Release(bufferParent
); /* once for the get parent */
1659 if (IUnknown_Release(bufferParent
) > 0) {
1660 FIXME("(%p) Something's still holding the back buffer\n",This
);
1664 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1665 object
->backBuffer
= NULL
;
1667 if(object
->context
[0])
1668 DestroyContext(This
, object
->context
[0]);
1669 if(object
->frontBuffer
) {
1670 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1671 IUnknown_Release(bufferParent
); /* once for the get parent */
1672 if (IUnknown_Release(bufferParent
) > 0) {
1673 FIXME("(%p) Something's still holding the front buffer\n",This
);
1676 HeapFree(GetProcessHeap(), 0, object
);
1680 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1681 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1682 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1683 TRACE("(%p)\n", This
);
1685 return This
->NumberOfSwapChains
;
1688 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1689 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1690 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1692 if(iSwapChain
< This
->NumberOfSwapChains
) {
1693 *pSwapChain
= This
->swapchains
[iSwapChain
];
1694 IWineD3DSwapChain_AddRef(*pSwapChain
);
1695 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1698 TRACE("Swapchain out of range\n");
1700 return WINED3DERR_INVALIDCALL
;
1705 * Vertex Declaration
1707 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1708 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, size_t element_count
) {
1709 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1710 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1711 HRESULT hr
= WINED3D_OK
;
1713 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1714 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1716 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1718 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1720 *ppVertexDeclaration
= NULL
;
1721 HeapFree(GetProcessHeap(), 0, object
);
1727 static size_t ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1728 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1730 unsigned int idx
, idx2
;
1731 unsigned int offset
;
1732 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1733 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1734 BOOL has_blend_idx
= has_blend
&&
1735 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1736 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1737 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1738 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1739 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1740 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1741 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1743 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1744 DWORD texcoords
= (fvf
& 0x00FF0000) >> 16;
1746 WINED3DVERTEXELEMENT end_element
= WINED3DDECL_END();
1747 WINED3DVERTEXELEMENT
*elements
= NULL
;
1750 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1751 if (has_blend_idx
) num_blends
--;
1753 /* Compute declaration size */
1754 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1755 has_psize
+ has_diffuse
+ has_specular
+ num_textures
+ 1;
1757 /* convert the declaration */
1758 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1762 memcpy(&elements
[size
-1], &end_element
, sizeof(WINED3DVERTEXELEMENT
));
1765 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1766 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1767 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITIONT
;
1770 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1771 elements
[idx
].Usage
= WINED3DDECLUSAGE_POSITION
;
1773 elements
[idx
].UsageIndex
= 0;
1776 if (has_blend
&& (num_blends
> 0)) {
1777 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1778 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1780 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
+ num_blends
- 1;
1781 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1782 elements
[idx
].UsageIndex
= 0;
1785 if (has_blend_idx
) {
1786 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1787 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1788 elements
[idx
].Type
= WINED3DDECLTYPE_UBYTE4
;
1789 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1790 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1792 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1793 elements
[idx
].Usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1794 elements
[idx
].UsageIndex
= 0;
1798 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1799 elements
[idx
].Usage
= WINED3DDECLUSAGE_NORMAL
;
1800 elements
[idx
].UsageIndex
= 0;
1804 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1805 elements
[idx
].Usage
= WINED3DDECLUSAGE_PSIZE
;
1806 elements
[idx
].UsageIndex
= 0;
1810 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1811 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1812 elements
[idx
].UsageIndex
= 0;
1816 elements
[idx
].Type
= WINED3DDECLTYPE_D3DCOLOR
;
1817 elements
[idx
].Usage
= WINED3DDECLUSAGE_COLOR
;
1818 elements
[idx
].UsageIndex
= 1;
1821 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1822 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1823 switch (numcoords
) {
1824 case WINED3DFVF_TEXTUREFORMAT1
:
1825 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT1
;
1827 case WINED3DFVF_TEXTUREFORMAT2
:
1828 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT2
;
1830 case WINED3DFVF_TEXTUREFORMAT3
:
1831 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT3
;
1833 case WINED3DFVF_TEXTUREFORMAT4
:
1834 elements
[idx
].Type
= WINED3DDECLTYPE_FLOAT4
;
1837 elements
[idx
].Usage
= WINED3DDECLUSAGE_TEXCOORD
;
1838 elements
[idx
].UsageIndex
= idx2
;
1842 /* Now compute offsets, and initialize the rest of the fields */
1843 for (idx
= 0, offset
= 0; idx
< size
-1; idx
++) {
1844 elements
[idx
].Stream
= 0;
1845 elements
[idx
].Method
= WINED3DDECLMETHOD_DEFAULT
;
1846 elements
[idx
].Offset
= offset
;
1847 offset
+= WINED3D_ATR_SIZE(elements
[idx
].Type
) * WINED3D_ATR_TYPESIZE(elements
[idx
].Type
);
1850 *ppVertexElements
= elements
;
1854 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
1855 WINED3DVERTEXELEMENT
* elements
= NULL
;
1856 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1860 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
1861 if (size
== 0) return WINED3DERR_OUTOFVIDEOMEMORY
;
1863 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
1864 HeapFree(GetProcessHeap(), 0, elements
);
1865 if (hr
!= S_OK
) return hr
;
1870 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1871 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1872 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1873 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1874 HRESULT hr
= WINED3D_OK
;
1875 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1876 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1878 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1880 if (vertex_declaration
) {
1881 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1884 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1886 if (WINED3D_OK
!= hr
) {
1887 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1888 IWineD3DVertexShader_Release(*ppVertexShader
);
1889 return WINED3DERR_INVALIDCALL
;
1895 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1897 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1898 HRESULT hr
= WINED3D_OK
;
1900 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1901 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1902 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1903 if (WINED3D_OK
== hr
) {
1904 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1906 WARN("(%p) : Failed to create pixel shader\n", This
);
1912 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1913 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1914 IWineD3DPaletteImpl
*object
;
1916 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1918 /* Create the new object */
1919 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1921 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1922 return E_OUTOFMEMORY
;
1925 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1927 object
->Flags
= Flags
;
1928 object
->parent
= Parent
;
1929 object
->wineD3DDevice
= This
;
1930 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1932 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1935 HeapFree( GetProcessHeap(), 0, object
);
1936 return E_OUTOFMEMORY
;
1939 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1941 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1945 *Palette
= (IWineD3DPalette
*) object
;
1950 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1954 HDC dcb
= NULL
, dcs
= NULL
;
1955 WINEDDCOLORKEY colorkey
;
1957 hbm
= (HBITMAP
) LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1960 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1961 dcb
= CreateCompatibleDC(NULL
);
1963 SelectObject(dcb
, hbm
);
1967 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1968 * couldn't be loaded
1970 memset(&bm
, 0, sizeof(bm
));
1975 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
1976 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
1977 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, NULL
, SURFACE_OPENGL
, NULL
);
1979 ERR("Wine logo requested, but failed to create surface\n");
1984 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1985 if(FAILED(hr
)) goto out
;
1986 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1987 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1989 colorkey
.dwColorSpaceLowValue
= 0;
1990 colorkey
.dwColorSpaceHighValue
= 0;
1991 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1993 /* Fill the surface with a white color to show that wined3d is there */
1994 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2007 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
2008 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2009 IWineD3DSwapChainImpl
*swapchain
;
2013 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
2014 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2016 /* TODO: Test if OpenGL is compiled in and loaded */
2018 TRACE("(%p) : Creating stateblock\n", This
);
2019 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2020 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2022 (IWineD3DStateBlock
**)&This
->stateBlock
,
2024 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2025 WARN("Failed to create stateblock\n");
2028 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2029 This
->updateStateBlock
= This
->stateBlock
;
2030 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2032 hr
= allocate_shader_constants(This
->updateStateBlock
);
2033 if (WINED3D_OK
!= hr
) {
2037 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2038 This
->fbo_color_attachments
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2039 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2041 /* Initialize the texture unit mapping to a 1:1 mapping */
2042 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2043 if (state
< GL_LIMITS(fragment_samplers
)) {
2044 This
->texUnitMap
[state
] = state
;
2045 This
->rev_tex_unit_map
[state
] = state
;
2047 This
->texUnitMap
[state
] = -1;
2048 This
->rev_tex_unit_map
[state
] = -1;
2052 /* Setup the implicit swapchain */
2053 TRACE("Creating implicit swapchain\n");
2054 hr
=D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2055 if (FAILED(hr
) || !swapchain
) {
2056 WARN("Failed to create implicit swapchain\n");
2060 This
->NumberOfSwapChains
= 1;
2061 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2062 if(!This
->swapchains
) {
2063 ERR("Out of memory!\n");
2066 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2068 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2069 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2070 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2071 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2074 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2075 This
->render_targets
[0] = swapchain
->frontBuffer
;
2076 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2078 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2079 This
->activeContext
= swapchain
->context
[0];
2080 This
->lastThread
= GetCurrentThreadId();
2082 /* Depth Stencil support */
2083 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2084 if (NULL
!= This
->stencilBufferTarget
) {
2085 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2088 /* Set up some starting GL setup */
2091 /* Setup all the devices defaults */
2092 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2094 IWineD3DImpl_CheckGraphicsMemory();
2097 { /* Set a default viewport */
2101 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
2102 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
2105 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2108 /* Initialize the current view state */
2109 This
->view_ident
= 1;
2110 This
->contexts
[0]->last_was_rhw
= 0;
2111 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2112 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2114 switch(wined3d_settings
.offscreen_rendering_mode
) {
2117 This
->offscreenBuffer
= GL_BACK
;
2120 case ORM_BACKBUFFER
:
2122 if(GL_LIMITS(aux_buffers
) > 0) {
2123 TRACE("Using auxilliary buffer for offscreen rendering\n");
2124 This
->offscreenBuffer
= GL_AUX0
;
2126 TRACE("Using back buffer for offscreen rendering\n");
2127 This
->offscreenBuffer
= GL_BACK
;
2132 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2135 /* Clear the screen */
2136 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2137 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2140 This
->d3d_initialized
= TRUE
;
2142 if(wined3d_settings
.logo
) {
2143 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2148 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2149 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2150 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2151 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2152 This
->NumberOfSwapChains
= 0;
2154 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2156 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2157 if(This
->stateBlock
) {
2158 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2159 This
->stateBlock
= NULL
;
2164 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2165 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2168 TRACE("(%p)\n", This
);
2170 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2172 /* I don't think that the interface guarants that the device is destroyed from the same thread
2173 * it was created. Thus make sure a context is active for the glDelete* calls
2175 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2177 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2179 TRACE("Deleting high order patches\n");
2180 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2181 struct list
*e1
, *e2
;
2182 struct WineD3DRectPatch
*patch
;
2183 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2184 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2185 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2189 /* Delete the palette conversion shader if it is around */
2190 if(This
->paletteConversionShader
) {
2191 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2192 This
->paletteConversionShader
= 0;
2195 /* Delete the pbuffer context if there is any */
2196 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2198 /* Delete the mouse cursor texture */
2199 if(This
->cursorTexture
) {
2201 glDeleteTextures(1, &This
->cursorTexture
);
2203 This
->cursorTexture
= 0;
2206 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2207 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2209 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2210 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2213 /* Release the update stateblock */
2214 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2215 if(This
->updateStateBlock
!= This
->stateBlock
)
2216 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2218 This
->updateStateBlock
= NULL
;
2220 { /* because were not doing proper internal refcounts releasing the primary state block
2221 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2222 to set this->stateBlock = NULL; first */
2223 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2224 This
->stateBlock
= NULL
;
2226 /* Release the stateblock */
2227 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2228 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2232 /* Release the buffers (with sanity checks)*/
2233 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2234 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2235 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2236 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2238 This
->stencilBufferTarget
= NULL
;
2240 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2241 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2242 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2244 TRACE("Setting rendertarget to NULL\n");
2245 This
->render_targets
[0] = NULL
;
2247 if (This
->auto_depth_stencil_buffer
) {
2248 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2249 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2251 This
->auto_depth_stencil_buffer
= NULL
;
2254 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2255 TRACE("Releasing the implicit swapchain %d\n", i
);
2256 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2257 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2261 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2262 This
->swapchains
= NULL
;
2263 This
->NumberOfSwapChains
= 0;
2265 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2266 HeapFree(GetProcessHeap(), 0, This
->fbo_color_attachments
);
2267 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2268 This
->render_targets
= NULL
;
2269 This
->fbo_color_attachments
= NULL
;
2270 This
->draw_buffers
= NULL
;
2273 This
->d3d_initialized
= FALSE
;
2277 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2278 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2279 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2281 /* Setup the window for fullscreen mode */
2282 if(fullscreen
&& !This
->ddraw_fullscreen
) {
2283 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
2284 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
2285 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
2288 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2289 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2290 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2293 This
->ddraw_fullscreen
= fullscreen
;
2296 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2297 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2298 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2300 * There is no way to deactivate thread safety once it is enabled.
2302 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2305 /*For now just store the flag(needed in case of ddraw) */
2306 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2311 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2313 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2315 const StaticPixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
, NULL
, NULL
);
2318 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2320 /* Resize the screen even without a window:
2321 * The app could have unset it with SetCooperativeLevel, but not called
2322 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2323 * but we don't have any hwnd
2326 memset(&devmode
, 0, sizeof(devmode
));
2327 devmode
.dmSize
= sizeof(devmode
);
2328 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2329 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2330 devmode
.dmPelsWidth
= pMode
->Width
;
2331 devmode
.dmPelsHeight
= pMode
->Height
;
2333 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2334 if (pMode
->RefreshRate
!= 0) {
2335 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2338 /* Only change the mode if necessary */
2339 if( (This
->ddraw_width
== pMode
->Width
) &&
2340 (This
->ddraw_height
== pMode
->Height
) &&
2341 (This
->ddraw_format
== pMode
->Format
) &&
2342 (pMode
->RefreshRate
== 0) ) {
2346 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2347 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2348 if(devmode
.dmDisplayFrequency
!= 0) {
2349 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2350 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2351 devmode
.dmDisplayFrequency
= 0;
2352 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2354 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2355 return WINED3DERR_NOTAVAILABLE
;
2359 /* Store the new values */
2360 This
->ddraw_width
= pMode
->Width
;
2361 This
->ddraw_height
= pMode
->Height
;
2362 This
->ddraw_format
= pMode
->Format
;
2364 /* Only do this with a window of course */
2365 if(This
->ddraw_window
)
2366 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2368 /* And finally clip mouse to our screen */
2369 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2370 ClipCursor(&clip_rc
);
2375 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2376 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2377 *ppD3D
= This
->wineD3D
;
2378 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2379 IWineD3D_AddRef(*ppD3D
);
2383 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2384 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2386 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2387 (This
->adapter
->TextureRam
/(1024*1024)),
2388 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2389 /* return simulated texture memory left */
2390 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2398 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2399 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2401 /* Update the current state block */
2402 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2404 if(This
->updateStateBlock
->fvf
== fvf
) {
2405 TRACE("Application is setting the old fvf over, nothing to do\n");
2409 This
->updateStateBlock
->fvf
= fvf
;
2410 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2411 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2416 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2417 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2418 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2419 *pfvf
= This
->stateBlock
->fvf
;
2424 * Get / Set Stream Source
2426 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2427 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2428 IWineD3DVertexBuffer
*oldSrc
;
2430 if (StreamNumber
>= MAX_STREAMS
) {
2431 WARN("Stream out of range %d\n", StreamNumber
);
2432 return WINED3DERR_INVALIDCALL
;
2433 } else if(OffsetInBytes
& 0x3) {
2434 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2435 return WINED3DERR_INVALIDCALL
;
2438 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2439 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2441 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2443 if(oldSrc
== pStreamData
&&
2444 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2445 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2446 TRACE("Application is setting the old values over, nothing to do\n");
2450 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2452 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2453 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2456 /* Handle recording of state blocks */
2457 if (This
->isRecordingState
) {
2458 TRACE("Recording... not performing anything\n");
2459 if(pStreamData
) IWineD3DVertexBuffer_AddRef(pStreamData
);
2460 if(oldSrc
) IWineD3DVertexBuffer_Release(oldSrc
);
2464 /* Need to do a getParent and pass the reffs up */
2465 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2466 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2467 so for now, just count internally */
2468 if (pStreamData
!= NULL
) {
2469 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2470 InterlockedIncrement(&vbImpl
->bindCount
);
2471 IWineD3DVertexBuffer_AddRef(pStreamData
);
2473 if (oldSrc
!= NULL
) {
2474 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2475 IWineD3DVertexBuffer_Release(oldSrc
);
2478 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2483 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2484 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2486 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2487 This
->stateBlock
->streamSource
[StreamNumber
],
2488 This
->stateBlock
->streamOffset
[StreamNumber
],
2489 This
->stateBlock
->streamStride
[StreamNumber
]);
2491 if (StreamNumber
>= MAX_STREAMS
) {
2492 WARN("Stream out of range %d\n", StreamNumber
);
2493 return WINED3DERR_INVALIDCALL
;
2495 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2496 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2498 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2501 if (*pStream
!= NULL
) {
2502 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2507 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2508 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2509 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2510 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2512 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2513 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2515 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2516 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2518 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2519 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2520 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2526 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2527 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2529 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2530 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2532 TRACE("(%p) : returning %d\n", This
, *Divider
);
2538 * Get / Set & Multiply Transform
2540 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2541 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2543 /* Most of this routine, comments included copied from ddraw tree initially: */
2544 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2546 /* Handle recording of state blocks */
2547 if (This
->isRecordingState
) {
2548 TRACE("Recording... not performing anything\n");
2549 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2550 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2555 * If the new matrix is the same as the current one,
2556 * we cut off any further processing. this seems to be a reasonable
2557 * optimization because as was noticed, some apps (warcraft3 for example)
2558 * tend towards setting the same matrix repeatedly for some reason.
2560 * From here on we assume that the new matrix is different, wherever it matters.
2562 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2563 TRACE("The app is setting the same matrix over again\n");
2566 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2570 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2571 where ViewMat = Camera space, WorldMat = world space.
2573 In OpenGL, camera and world space is combined into GL_MODELVIEW
2574 matrix. The Projection matrix stay projection matrix.
2577 /* Capture the times we can just ignore the change for now */
2578 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2579 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2580 /* Handled by the state manager */
2583 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2587 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2588 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2589 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2590 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2594 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2595 WINED3DMATRIX
*mat
= NULL
;
2598 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2599 * below means it will be recorded in a state block change, but it
2600 * works regardless where it is recorded.
2601 * If this is found to be wrong, change to StateBlock.
2603 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2604 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2606 if (State
< HIGHEST_TRANSFORMSTATE
)
2608 mat
= &This
->updateStateBlock
->transforms
[State
];
2610 FIXME("Unhandled transform state!!\n");
2613 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2615 /* Apply change via set transform - will reapply to eg. lights this way */
2616 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2622 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2623 you can reference any indexes you want as long as that number max are enabled at any
2624 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2625 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2626 but when recording, just build a chain pretty much of commands to be replayed. */
2628 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2630 PLIGHTINFOEL
*object
= NULL
;
2631 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2634 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2635 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2637 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2641 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2642 return WINED3DERR_INVALIDCALL
;
2645 switch(pLight
->Type
) {
2646 case WINED3DLIGHT_POINT
:
2647 case WINED3DLIGHT_SPOT
:
2648 case WINED3DLIGHT_PARALLELPOINT
:
2649 case WINED3DLIGHT_GLSPOT
:
2650 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2653 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
2654 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL
;
2659 case WINED3DLIGHT_DIRECTIONAL
:
2660 /* Ignores attenuation */
2664 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2665 return WINED3DERR_INVALIDCALL
;
2668 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2669 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2670 if(object
->OriginalIndex
== Index
) break;
2675 TRACE("Adding new light\n");
2676 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2678 ERR("Out of memory error when allocating a light\n");
2679 return E_OUTOFMEMORY
;
2681 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2682 object
->glIndex
= -1;
2683 object
->OriginalIndex
= Index
;
2684 object
->changed
= TRUE
;
2687 /* Initialize the object */
2688 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
,
2689 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2690 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2691 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2692 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2693 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2694 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2696 /* Save away the information */
2697 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2699 switch (pLight
->Type
) {
2700 case WINED3DLIGHT_POINT
:
2702 object
->lightPosn
[0] = pLight
->Position
.x
;
2703 object
->lightPosn
[1] = pLight
->Position
.y
;
2704 object
->lightPosn
[2] = pLight
->Position
.z
;
2705 object
->lightPosn
[3] = 1.0f
;
2706 object
->cutoff
= 180.0f
;
2710 case WINED3DLIGHT_DIRECTIONAL
:
2712 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2713 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2714 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2715 object
->lightPosn
[3] = 0.0;
2716 object
->exponent
= 0.0f
;
2717 object
->cutoff
= 180.0f
;
2720 case WINED3DLIGHT_SPOT
:
2722 object
->lightPosn
[0] = pLight
->Position
.x
;
2723 object
->lightPosn
[1] = pLight
->Position
.y
;
2724 object
->lightPosn
[2] = pLight
->Position
.z
;
2725 object
->lightPosn
[3] = 1.0;
2728 object
->lightDirn
[0] = pLight
->Direction
.x
;
2729 object
->lightDirn
[1] = pLight
->Direction
.y
;
2730 object
->lightDirn
[2] = pLight
->Direction
.z
;
2731 object
->lightDirn
[3] = 1.0;
2734 * opengl-ish and d3d-ish spot lights use too different models for the
2735 * light "intensity" as a function of the angle towards the main light direction,
2736 * so we only can approximate very roughly.
2737 * however spot lights are rather rarely used in games (if ever used at all).
2738 * furthermore if still used, probably nobody pays attention to such details.
2740 if (pLight
->Falloff
== 0) {
2741 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2742 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2743 * will always be 1.0 for both of them, and we don't have to care for the
2744 * rest of the rather complex calculation
2746 object
->exponent
= 0;
2748 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2749 if (rho
< 0.0001) rho
= 0.0001f
;
2750 object
->exponent
= -0.3/log(cos(rho
/2));
2752 if (object
->exponent
> 128.0) {
2753 object
->exponent
= 128.0;
2755 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2761 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2764 /* Update the live definitions if the light is currently assigned a glIndex */
2765 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2766 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2771 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2772 PLIGHTINFOEL
*lightInfo
= NULL
;
2773 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2774 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2776 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2778 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2779 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2780 if(lightInfo
->OriginalIndex
== Index
) break;
2784 if (lightInfo
== NULL
) {
2785 TRACE("Light information requested but light not defined\n");
2786 return WINED3DERR_INVALIDCALL
;
2789 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2794 * Get / Set Light Enable
2795 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2797 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2798 PLIGHTINFOEL
*lightInfo
= NULL
;
2799 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2800 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2802 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2804 /* Tests show true = 128...not clear why */
2805 Enable
= Enable
? 128: 0;
2807 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2808 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2809 if(lightInfo
->OriginalIndex
== Index
) break;
2812 TRACE("Found light: %p\n", lightInfo
);
2814 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2815 if (lightInfo
== NULL
) {
2817 TRACE("Light enabled requested but light not defined, so defining one!\n");
2818 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2820 /* Search for it again! Should be fairly quick as near head of list */
2821 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2822 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2823 if(lightInfo
->OriginalIndex
== Index
) break;
2826 if (lightInfo
== NULL
) {
2827 FIXME("Adding default lights has failed dismally\n");
2828 return WINED3DERR_INVALIDCALL
;
2832 lightInfo
->enabledChanged
= TRUE
;
2834 if(lightInfo
->glIndex
!= -1) {
2835 if(!This
->isRecordingState
) {
2836 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2839 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2840 lightInfo
->glIndex
= -1;
2842 TRACE("Light already disabled, nothing to do\n");
2844 lightInfo
->enabled
= FALSE
;
2846 lightInfo
->enabled
= TRUE
;
2847 if (lightInfo
->glIndex
!= -1) {
2849 TRACE("Nothing to do as light was enabled\n");
2852 /* Find a free gl light */
2853 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2854 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2855 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2856 lightInfo
->glIndex
= i
;
2860 if(lightInfo
->glIndex
== -1) {
2861 /* Our tests show that Windows returns D3D_OK in this situation, even with
2862 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2863 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2864 * as well for those lights.
2866 * TODO: Test how this affects rendering
2868 FIXME("Too many concurrently active lights\n");
2872 /* i == lightInfo->glIndex */
2873 if(!This
->isRecordingState
) {
2874 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2882 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2884 PLIGHTINFOEL
*lightInfo
= NULL
;
2885 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2887 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2888 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2890 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2891 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2892 if(lightInfo
->OriginalIndex
== Index
) break;
2896 if (lightInfo
== NULL
) {
2897 TRACE("Light enabled state requested but light not defined\n");
2898 return WINED3DERR_INVALIDCALL
;
2900 /* true is 128 according to SetLightEnable */
2901 *pEnable
= lightInfo
->enabled
? 128 : 0;
2906 * Get / Set Clip Planes
2908 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2909 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2910 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2912 /* Validate Index */
2913 if (Index
>= GL_LIMITS(clipplanes
)) {
2914 TRACE("Application has requested clipplane this device doesn't support\n");
2915 return WINED3DERR_INVALIDCALL
;
2918 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2920 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2921 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2922 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2923 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2924 TRACE("Application is setting old values over, nothing to do\n");
2928 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2929 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2930 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2931 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2933 /* Handle recording of state blocks */
2934 if (This
->isRecordingState
) {
2935 TRACE("Recording... not performing anything\n");
2939 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2944 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2945 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2946 TRACE("(%p) : for idx %d\n", This
, Index
);
2948 /* Validate Index */
2949 if (Index
>= GL_LIMITS(clipplanes
)) {
2950 TRACE("Application has requested clipplane this device doesn't support\n");
2951 return WINED3DERR_INVALIDCALL
;
2954 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2955 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2956 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2957 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2962 * Get / Set Clip Plane Status
2963 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2965 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2966 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2967 FIXME("(%p) : stub\n", This
);
2968 if (NULL
== pClipStatus
) {
2969 return WINED3DERR_INVALIDCALL
;
2971 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2972 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2976 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2977 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2978 FIXME("(%p) : stub\n", This
);
2979 if (NULL
== pClipStatus
) {
2980 return WINED3DERR_INVALIDCALL
;
2982 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2983 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2988 * Get / Set Material
2990 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2991 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2993 This
->updateStateBlock
->changed
.material
= TRUE
;
2994 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2996 /* Handle recording of state blocks */
2997 if (This
->isRecordingState
) {
2998 TRACE("Recording... not performing anything\n");
3002 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3006 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3007 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3008 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
3009 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3010 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3011 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3012 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3013 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3014 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3015 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3016 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3017 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3025 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
) {
3026 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3027 IWineD3DIndexBuffer
*oldIdxs
;
3029 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3030 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3032 This
->updateStateBlock
->changed
.indices
= TRUE
;
3033 This
->updateStateBlock
->pIndexData
= pIndexData
;
3035 /* Handle recording of state blocks */
3036 if (This
->isRecordingState
) {
3037 TRACE("Recording... not performing anything\n");
3038 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3039 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3043 if(oldIdxs
!= pIndexData
) {
3044 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3045 if(pIndexData
) IWineD3DIndexBuffer_AddRef(pIndexData
);
3046 if(oldIdxs
) IWineD3DIndexBuffer_Release(oldIdxs
);
3051 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
) {
3052 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3054 *ppIndexData
= This
->stateBlock
->pIndexData
;
3056 /* up ref count on ppindexdata */
3058 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3059 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3061 TRACE("(%p) No index data set\n", This
);
3063 TRACE("Returning %p\n", *ppIndexData
);
3068 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3069 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3070 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3071 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3073 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3074 TRACE("Application is setting the old value over, nothing to do\n");
3078 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3080 if (This
->isRecordingState
) {
3081 TRACE("Recording... not performing anything\n");
3084 /* The base vertex index affects the stream sources */
3085 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3089 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3090 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3091 TRACE("(%p) : base_index %p\n", This
, base_index
);
3093 *base_index
= This
->stateBlock
->baseVertexIndex
;
3095 TRACE("Returning %u\n", *base_index
);
3101 * Get / Set Viewports
3103 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3104 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3106 TRACE("(%p)\n", This
);
3107 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3108 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
3110 /* Handle recording of state blocks */
3111 if (This
->isRecordingState
) {
3112 TRACE("Recording... not performing anything\n");
3116 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3117 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3119 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3124 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3125 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3126 TRACE("(%p)\n", This
);
3127 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
3132 * Get / Set Render States
3133 * TODO: Verify against dx9 definitions
3135 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3138 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3140 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3142 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3143 This
->updateStateBlock
->renderState
[State
] = Value
;
3145 /* Handle recording of state blocks */
3146 if (This
->isRecordingState
) {
3147 TRACE("Recording... not performing anything\n");
3151 /* Compared here and not before the assignment to allow proper stateblock recording */
3152 if(Value
== oldValue
) {
3153 TRACE("Application is setting the old value over, nothing to do\n");
3155 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3161 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3162 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3163 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3164 *pValue
= This
->stateBlock
->renderState
[State
];
3169 * Get / Set Sampler States
3170 * TODO: Verify against dx9 definitions
3173 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3174 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3177 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3178 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3180 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3181 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3185 * SetSampler is designed to allow for more than the standard up to 8 textures
3186 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3187 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3189 * http://developer.nvidia.com/object/General_FAQ.html#t6
3191 * There are two new settings for GForce
3193 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3194 * and the texture one:
3195 * GL_MAX_TEXTURE_COORDS_ARB.
3196 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3199 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3200 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3201 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3203 /* Handle recording of state blocks */
3204 if (This
->isRecordingState
) {
3205 TRACE("Recording... not performing anything\n");
3209 if(oldValue
== Value
) {
3210 TRACE("Application is setting the old value over, nothing to do\n");
3214 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3219 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3220 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3222 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3223 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3225 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3226 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3229 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3230 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3235 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3236 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3238 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3239 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3240 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3243 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3245 if(This
->isRecordingState
) {
3246 TRACE("Recording... not performing anything\n");
3250 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3255 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3256 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3258 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
3259 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3263 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3264 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3265 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3267 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3269 This
->updateStateBlock
->vertexDecl
= pDecl
;
3270 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3272 if (This
->isRecordingState
) {
3273 TRACE("Recording... not performing anything\n");
3275 } else if(pDecl
== oldDecl
) {
3276 /* Checked after the assignment to allow proper stateblock recording */
3277 TRACE("Application is setting the old declaration over, nothing to do\n");
3281 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3285 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3286 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3288 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3290 *ppDecl
= This
->stateBlock
->vertexDecl
;
3291 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3295 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3296 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3297 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3299 This
->updateStateBlock
->vertexShader
= pShader
;
3300 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3302 if (This
->isRecordingState
) {
3303 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3304 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3305 TRACE("Recording... not performing anything\n");
3307 } else if(oldShader
== pShader
) {
3308 /* Checked here to allow proper stateblock recording */
3309 TRACE("App is setting the old shader over, nothing to do\n");
3313 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3314 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3315 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3317 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3322 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3323 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3325 if (NULL
== ppShader
) {
3326 return WINED3DERR_INVALIDCALL
;
3328 *ppShader
= This
->stateBlock
->vertexShader
;
3329 if( NULL
!= *ppShader
)
3330 IWineD3DVertexShader_AddRef(*ppShader
);
3332 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3336 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3337 IWineD3DDevice
*iface
,
3339 CONST BOOL
*srcData
,
3342 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3343 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3345 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3346 iface
, srcData
, start
, count
);
3348 if (srcData
== NULL
|| cnt
< 0)
3349 return WINED3DERR_INVALIDCALL
;
3351 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3352 for (i
= 0; i
< cnt
; i
++)
3353 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3355 for (i
= start
; i
< cnt
+ start
; ++i
) {
3356 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3359 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3364 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3365 IWineD3DDevice
*iface
,
3370 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3371 int cnt
= min(count
, MAX_CONST_B
- start
);
3373 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3374 iface
, dstData
, start
, count
);
3376 if (dstData
== NULL
|| cnt
< 0)
3377 return WINED3DERR_INVALIDCALL
;
3379 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3383 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3384 IWineD3DDevice
*iface
,
3389 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3390 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3392 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3393 iface
, srcData
, start
, count
);
3395 if (srcData
== NULL
|| cnt
< 0)
3396 return WINED3DERR_INVALIDCALL
;
3398 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3399 for (i
= 0; i
< cnt
; i
++)
3400 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3401 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3403 for (i
= start
; i
< cnt
+ start
; ++i
) {
3404 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3407 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3412 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3413 IWineD3DDevice
*iface
,
3418 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3419 int cnt
= min(count
, MAX_CONST_I
- start
);
3421 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3422 iface
, dstData
, start
, count
);
3424 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3425 return WINED3DERR_INVALIDCALL
;
3427 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3431 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3432 IWineD3DDevice
*iface
,
3434 CONST
float *srcData
,
3437 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3440 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3441 iface
, srcData
, start
, count
);
3443 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3444 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(vshader_constantsF
) || start
> GL_LIMITS(vshader_constantsF
))
3445 return WINED3DERR_INVALIDCALL
;
3447 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3449 for (i
= 0; i
< count
; i
++)
3450 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3451 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3454 for (i
= start
; i
< count
+ start
; ++i
) {
3455 if (!This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
]) {
3456 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_vconstantsF
), constants_entry
, entry
);
3457 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3458 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3459 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3461 ptr
->idx
[ptr
->count
++] = i
;
3462 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3466 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3471 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3472 IWineD3DDevice
*iface
,
3477 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3478 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3480 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3481 iface
, dstData
, start
, count
);
3483 if (dstData
== NULL
|| cnt
< 0)
3484 return WINED3DERR_INVALIDCALL
;
3486 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3490 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3492 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3493 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3497 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
3498 int i
= This
->rev_tex_unit_map
[unit
];
3499 int j
= This
->texUnitMap
[stage
];
3501 This
->texUnitMap
[stage
] = unit
;
3502 if (i
!= -1 && i
!= stage
) {
3503 This
->texUnitMap
[i
] = -1;
3506 This
->rev_tex_unit_map
[unit
] = stage
;
3507 if (j
!= -1 && j
!= unit
) {
3508 This
->rev_tex_unit_map
[j
] = -1;
3512 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3515 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3516 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3517 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3518 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3519 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3520 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3521 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3522 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3523 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3525 if (color_op
== WINED3DTOP_DISABLE
) {
3526 /* Not used, and disable higher stages */
3527 while (i
< MAX_TEXTURES
) {
3528 This
->fixed_function_usage_map
[i
] = FALSE
;
3534 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3535 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3536 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3537 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3538 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3539 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3540 This
->fixed_function_usage_map
[i
] = TRUE
;
3542 This
->fixed_function_usage_map
[i
] = FALSE
;
3545 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3546 This
->fixed_function_usage_map
[i
+1] = TRUE
;
3551 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3554 device_update_fixed_function_usage_map(This
);
3556 if (!GL_SUPPORT(NV_REGISTER_COMBINERS
) || This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3557 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3558 if (!This
->fixed_function_usage_map
[i
]) continue;
3560 if (This
->texUnitMap
[i
] != i
) {
3561 device_map_stage(This
, i
, i
);
3562 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3563 markTextureStagesDirty(This
, i
);
3569 /* Now work out the mapping */
3571 for (i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; ++i
) {
3572 if (!This
->fixed_function_usage_map
[i
]) continue;
3574 if (This
->texUnitMap
[i
] != tex
) {
3575 device_map_stage(This
, i
, tex
);
3576 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3577 markTextureStagesDirty(This
, i
);
3584 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3585 DWORD
*sampler_tokens
= ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
3588 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3589 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
3590 device_map_stage(This
, i
, i
);
3591 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3592 if (i
< MAX_TEXTURES
) {
3593 markTextureStagesDirty(This
, i
);
3599 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, DWORD
*pshader_sampler_tokens
, DWORD
*vshader_sampler_tokens
, int unit
) {
3600 int current_mapping
= This
->rev_tex_unit_map
[unit
];
3602 if (current_mapping
== -1) {
3603 /* Not currently used */
3607 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3608 /* Used by a fragment sampler */
3610 if (!pshader_sampler_tokens
) {
3611 /* No pixel shader, check fixed function */
3612 return current_mapping
>= MAX_TEXTURES
|| !This
->fixed_function_usage_map
[current_mapping
];
3615 /* Pixel shader, check the shader's sampler map */
3616 return !pshader_sampler_tokens
[current_mapping
];
3619 /* Used by a vertex sampler */
3620 return !vshader_sampler_tokens
[current_mapping
];
3623 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3624 DWORD
*vshader_sampler_tokens
= ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
3625 DWORD
*pshader_sampler_tokens
= NULL
;
3626 int start
= GL_LIMITS(combined_samplers
) - 1;
3630 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3632 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3633 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader
*)pshader
);
3634 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
3637 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3638 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3639 if (vshader_sampler_tokens
[i
]) {
3640 if (This
->texUnitMap
[vsampler_idx
] != -1) {
3641 /* Already mapped somewhere */
3645 while (start
>= 0) {
3646 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
3647 device_map_stage(This
, vsampler_idx
, start
);
3648 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3660 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3661 BOOL vs
= use_vs(This
);
3662 BOOL ps
= use_ps(This
);
3665 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3666 * that would be really messy and require shader recompilation
3667 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3668 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3671 device_map_psamplers(This
);
3673 device_map_fixed_function_samplers(This
);
3677 device_map_vsamplers(This
, ps
);
3681 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3682 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3683 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3684 This
->updateStateBlock
->pixelShader
= pShader
;
3685 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3687 /* Handle recording of state blocks */
3688 if (This
->isRecordingState
) {
3689 TRACE("Recording... not performing anything\n");
3692 if (This
->isRecordingState
) {
3693 TRACE("Recording... not performing anything\n");
3694 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3695 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3699 if(pShader
== oldShader
) {
3700 TRACE("App is setting the old pixel shader over, nothing to do\n");
3704 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3705 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3707 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3708 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3713 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3714 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3716 if (NULL
== ppShader
) {
3717 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3718 return WINED3DERR_INVALIDCALL
;
3721 *ppShader
= This
->stateBlock
->pixelShader
;
3722 if (NULL
!= *ppShader
) {
3723 IWineD3DPixelShader_AddRef(*ppShader
);
3725 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3729 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3730 IWineD3DDevice
*iface
,
3732 CONST BOOL
*srcData
,
3735 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3736 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3738 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3739 iface
, srcData
, start
, count
);
3741 if (srcData
== NULL
|| cnt
< 0)
3742 return WINED3DERR_INVALIDCALL
;
3744 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3745 for (i
= 0; i
< cnt
; i
++)
3746 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3748 for (i
= start
; i
< cnt
+ start
; ++i
) {
3749 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3752 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3757 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3758 IWineD3DDevice
*iface
,
3763 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3764 int cnt
= min(count
, MAX_CONST_B
- start
);
3766 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3767 iface
, dstData
, start
, count
);
3769 if (dstData
== NULL
|| cnt
< 0)
3770 return WINED3DERR_INVALIDCALL
;
3772 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3776 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3777 IWineD3DDevice
*iface
,
3782 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3783 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3785 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3786 iface
, srcData
, start
, count
);
3788 if (srcData
== NULL
|| cnt
< 0)
3789 return WINED3DERR_INVALIDCALL
;
3791 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3792 for (i
= 0; i
< cnt
; i
++)
3793 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3794 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3796 for (i
= start
; i
< cnt
+ start
; ++i
) {
3797 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3800 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3805 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3806 IWineD3DDevice
*iface
,
3811 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3812 int cnt
= min(count
, MAX_CONST_I
- start
);
3814 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3815 iface
, dstData
, start
, count
);
3817 if (dstData
== NULL
|| cnt
< 0)
3818 return WINED3DERR_INVALIDCALL
;
3820 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3824 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3825 IWineD3DDevice
*iface
,
3827 CONST
float *srcData
,
3830 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3833 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3834 iface
, srcData
, start
, count
);
3836 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3837 if (srcData
== NULL
|| start
+ count
> GL_LIMITS(pshader_constantsF
) || start
> GL_LIMITS(pshader_constantsF
))
3838 return WINED3DERR_INVALIDCALL
;
3840 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3842 for (i
= 0; i
< count
; i
++)
3843 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3844 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3847 for (i
= start
; i
< count
+ start
; ++i
) {
3848 if (!This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
]) {
3849 constants_entry
*ptr
= LIST_ENTRY(list_head(&This
->updateStateBlock
->set_pconstantsF
), constants_entry
, entry
);
3850 if (!ptr
|| ptr
->count
>= sizeof(ptr
->idx
) / sizeof(*ptr
->idx
)) {
3851 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(constants_entry
));
3852 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3854 ptr
->idx
[ptr
->count
++] = i
;
3855 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3859 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3864 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3865 IWineD3DDevice
*iface
,
3870 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3871 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3873 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3874 iface
, dstData
, start
, count
);
3876 if (dstData
== NULL
|| cnt
< 0)
3877 return WINED3DERR_INVALIDCALL
;
3879 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3883 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3885 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3886 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3888 DWORD DestFVF
= dest
->fvf
;
3890 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3894 if (lpStrideData
->u
.s
.normal
.lpData
) {
3895 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3898 if (lpStrideData
->u
.s
.position
.lpData
== NULL
) {
3899 ERR("Source has no position mask\n");
3900 return WINED3DERR_INVALIDCALL
;
3903 /* We might access VBOs from this code, so hold the lock */
3906 if (dest
->resource
.allocatedMemory
== NULL
) {
3907 /* This may happen if we do direct locking into a vbo. Unlikely,
3908 * but theoretically possible(ddraw processvertices test)
3910 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3911 if(!dest
->resource
.allocatedMemory
) {
3913 ERR("Out of memory\n");
3914 return E_OUTOFMEMORY
;
3918 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3919 checkGLcall("glBindBufferARB");
3920 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3922 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3924 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3925 checkGLcall("glUnmapBufferARB");
3929 /* Get a pointer into the destination vbo(create one if none exists) and
3930 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3932 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3937 unsigned char extrabytes
= 0;
3938 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3939 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3940 * this may write 4 extra bytes beyond the area that should be written
3942 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3943 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3944 if(!dest_conv_addr
) {
3945 ERR("Out of memory\n");
3946 /* Continue without storing converted vertices */
3948 dest_conv
= dest_conv_addr
;
3952 * a) WINED3DRS_CLIPPING is enabled
3953 * b) WINED3DVOP_CLIP is passed
3955 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3956 static BOOL warned
= FALSE
;
3958 * The clipping code is not quite correct. Some things need
3959 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3960 * so disable clipping for now.
3961 * (The graphics in Half-Life are broken, and my processvertices
3962 * test crashes with IDirect3DDevice3)
3968 FIXME("Clipping is broken and disabled for now\n");
3970 } else doClip
= FALSE
;
3971 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3973 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3976 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3977 WINED3DTS_PROJECTION
,
3979 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3980 WINED3DTS_WORLDMATRIX(0),
3983 TRACE("View mat:\n");
3984 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
);
3985 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
);
3986 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
);
3987 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
);
3989 TRACE("Proj mat:\n");
3990 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
);
3991 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
);
3992 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
);
3993 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
);
3995 TRACE("World mat:\n");
3996 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
);
3997 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
);
3998 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
);
3999 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
);
4001 /* Get the viewport */
4002 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4003 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4004 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4006 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4007 multiply_matrix(&mat
,&proj_mat
,&mat
);
4009 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4011 for (i
= 0; i
< dwCount
; i
+= 1) {
4012 unsigned int tex_index
;
4014 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4015 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4016 /* The position first */
4018 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
4020 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4022 /* Multiplication with world, view and projection matrix */
4023 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
);
4024 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
);
4025 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
);
4026 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
);
4028 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4030 /* WARNING: The following things are taken from d3d7 and were not yet checked
4031 * against d3d8 or d3d9!
4034 /* Clipping conditions: From
4035 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4037 * A vertex is clipped if it does not match the following requirements
4041 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4043 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4044 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4049 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4050 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4053 /* "Normal" viewport transformation (not clipped)
4054 * 1) The values are divided by rhw
4055 * 2) The y axis is negative, so multiply it with -1
4056 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4057 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4058 * 4) Multiply x with Width/2 and add Width/2
4059 * 5) The same for the height
4060 * 6) Add the viewpoint X and Y to the 2D coordinates and
4061 * The minimum Z value to z
4062 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4064 * Well, basically it's simply a linear transformation into viewport
4076 z
*= vp
.MaxZ
- vp
.MinZ
;
4078 x
+= vp
.Width
/ 2 + vp
.X
;
4079 y
+= vp
.Height
/ 2 + vp
.Y
;
4084 /* That vertex got clipped
4085 * Contrary to OpenGL it is not dropped completely, it just
4086 * undergoes a different calculation.
4088 TRACE("Vertex got clipped\n");
4095 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4096 * outside of the main vertex buffer memory. That needs some more
4101 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4104 ( (float *) dest_ptr
)[0] = x
;
4105 ( (float *) dest_ptr
)[1] = y
;
4106 ( (float *) dest_ptr
)[2] = z
;
4107 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4109 dest_ptr
+= 3 * sizeof(float);
4111 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4112 dest_ptr
+= sizeof(float);
4117 ( (float *) dest_conv
)[0] = x
* w
;
4118 ( (float *) dest_conv
)[1] = y
* w
;
4119 ( (float *) dest_conv
)[2] = z
* w
;
4120 ( (float *) dest_conv
)[3] = w
;
4122 dest_conv
+= 3 * sizeof(float);
4124 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4125 dest_conv
+= sizeof(float);
4129 if (DestFVF
& WINED3DFVF_PSIZE
) {
4130 dest_ptr
+= sizeof(DWORD
);
4131 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4133 if (DestFVF
& WINED3DFVF_NORMAL
) {
4135 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4136 /* AFAIK this should go into the lighting information */
4137 FIXME("Didn't expect the destination to have a normal\n");
4138 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4140 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4144 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4146 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4148 static BOOL warned
= FALSE
;
4151 ERR("No diffuse color in source, but destination has one\n");
4155 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4156 dest_ptr
+= sizeof(DWORD
);
4159 *( (DWORD
*) dest_conv
) = 0xffffffff;
4160 dest_conv
+= sizeof(DWORD
);
4164 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4166 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4167 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4168 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4169 dest_conv
+= sizeof(DWORD
);
4174 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4175 /* What's the color value in the feedback buffer? */
4177 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4179 static BOOL warned
= FALSE
;
4182 ERR("No specular color in source, but destination has one\n");
4186 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4187 dest_ptr
+= sizeof(DWORD
);
4190 *( (DWORD
*) dest_conv
) = 0xFF000000;
4191 dest_conv
+= sizeof(DWORD
);
4195 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4197 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4198 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4199 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4200 dest_conv
+= sizeof(DWORD
);
4205 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4207 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4208 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4210 ERR("No source texture, but destination requests one\n");
4211 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4212 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4215 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4217 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4224 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
4225 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4226 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4227 dwCount
* get_flexible_vertex_size(DestFVF
),
4229 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4230 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4237 #undef copy_and_next
4239 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexDeclaration
* pVertexDecl
, DWORD Flags
) {
4240 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4241 WineDirect3DVertexStridedData strided
;
4242 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4243 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4246 ERR("Output vertex declaration not implemented yet\n");
4249 /* Need any context to write to the vbo. */
4250 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4252 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4253 * control the streamIsUP flag, thus restore it afterwards.
4255 This
->stateBlock
->streamIsUP
= FALSE
;
4256 memset(&strided
, 0, sizeof(strided
));
4257 primitiveDeclarationConvertToStridedData(iface
, FALSE
, &strided
, &vbo
);
4258 This
->stateBlock
->streamIsUP
= streamWasUP
;
4260 if(vbo
|| SrcStartIndex
) {
4262 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4263 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4265 * Also get the start index in, but only loop over all elements if there's something to add at all.
4267 #define FIXSRC(type) \
4268 if(strided.u.s.type.VBO) { \
4269 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4270 strided.u.s.type.VBO = 0; \
4271 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4273 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4277 if(strided.u.s.type.lpData) { \
4278 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4281 FIXSRC(blendWeights
);
4282 FIXSRC(blendMatrixIndices
);
4287 for(i
= 0; i
< WINED3DDP_MAXTEXCOORD
; i
++) {
4288 FIXSRC(texCoords
[i
]);
4301 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4305 * Get / Set Texture Stage States
4306 * TODO: Verify against dx9 definitions
4308 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4309 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4310 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4312 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4314 if (Stage
>= MAX_TEXTURES
) {
4315 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4319 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4320 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4322 if (This
->isRecordingState
) {
4323 TRACE("Recording... not performing anything\n");
4327 /* Checked after the assignments to allow proper stateblock recording */
4328 if(oldValue
== Value
) {
4329 TRACE("App is setting the old value over, nothing to do\n");
4333 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4334 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4335 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4336 * Changes in other states are important on disabled stages too
4341 if(Type
== WINED3DTSS_COLOROP
) {
4344 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4345 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4346 * they have to be disabled
4348 * The current stage is dirtified below.
4350 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4351 TRACE("Additionally dirtifying stage %d\n", i
);
4352 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4354 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4355 TRACE("New lowest disabled: %d\n", Stage
);
4356 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4357 /* Previously disabled stage enabled. Stages above it may need enabling
4358 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4359 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4361 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4364 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4365 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4368 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4369 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4371 This
->stateBlock
->lowest_disabled_stage
= i
;
4372 TRACE("New lowest disabled: %d\n", i
);
4374 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4375 /* TODO: Built a stage -> texture unit mapping for register combiners */
4379 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4384 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4385 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4386 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4387 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4394 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4395 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4396 IWineD3DBaseTexture
*oldTexture
;
4398 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
4400 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4401 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4404 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4406 if(pTexture
!= NULL
) {
4407 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4409 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4410 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4411 return WINED3DERR_INVALIDCALL
;
4413 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4416 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4417 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4419 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4420 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4421 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4423 /* Handle recording of state blocks */
4424 if (This
->isRecordingState
) {
4425 TRACE("Recording... not performing anything\n");
4429 if(oldTexture
== pTexture
) {
4430 TRACE("App is setting the same texture again, nothing to do\n");
4434 /** NOTE: MSDN says that setTexture increases the reference count,
4435 * and that the application must set the texture back to null (or have a leaky application),
4436 * This means we should pass the refcount up to the parent
4437 *******************************/
4438 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4439 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4440 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4442 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4443 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4444 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4445 * so the COLOROP and ALPHAOP have to be dirtified.
4447 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4448 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4450 if(bindCount
== 1) {
4451 new->baseTexture
.sampler
= Stage
;
4453 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4457 if (NULL
!= oldTexture
) {
4458 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4459 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4461 IWineD3DBaseTexture_Release(oldTexture
);
4462 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4463 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4464 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4467 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4469 /* Have to do a search for the other sampler(s) where the texture is bound to
4470 * Shouldn't happen as long as apps bind a texture only to one stage
4472 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4473 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4474 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4475 old
->baseTexture
.sampler
= i
;
4482 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4487 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4490 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4492 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4493 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4496 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4498 IWineD3DBaseTexture_AddRef(*ppTexture
);
4500 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4508 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4509 IWineD3DSurface
**ppBackBuffer
) {
4510 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4511 IWineD3DSwapChain
*swapChain
;
4514 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4516 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4517 if (hr
== WINED3D_OK
) {
4518 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4519 IWineD3DSwapChain_Release(swapChain
);
4521 *ppBackBuffer
= NULL
;
4526 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4527 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4528 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4529 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4532 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4533 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4534 IWineD3DSwapChain
*swapChain
;
4537 if(iSwapChain
> 0) {
4538 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4539 if (hr
== WINED3D_OK
) {
4540 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4541 IWineD3DSwapChain_Release(swapChain
);
4543 FIXME("(%p) Error getting display mode\n", This
);
4546 /* Don't read the real display mode,
4547 but return the stored mode instead. X11 can't change the color
4548 depth, and some apps are pretty angry if they SetDisplayMode from
4549 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4551 Also don't relay to the swapchain because with ddraw it's possible
4552 that there isn't a swapchain at all */
4553 pMode
->Width
= This
->ddraw_width
;
4554 pMode
->Height
= This
->ddraw_height
;
4555 pMode
->Format
= This
->ddraw_format
;
4556 pMode
->RefreshRate
= 0;
4563 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4564 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4565 TRACE("(%p)->(%p)\n", This
, hWnd
);
4567 if(This
->ddraw_fullscreen
) {
4568 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4569 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4571 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4572 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4576 This
->ddraw_window
= hWnd
;
4580 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4581 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4582 TRACE("(%p)->(%p)\n", This
, hWnd
);
4584 *hWnd
= This
->ddraw_window
;
4589 * Stateblock related functions
4592 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4593 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4594 IWineD3DStateBlockImpl
*object
;
4595 HRESULT temp_result
;
4598 TRACE("(%p)\n", This
);
4600 if (This
->isRecordingState
) {
4601 return WINED3DERR_INVALIDCALL
;
4604 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4605 if (NULL
== object
) {
4606 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4607 return E_OUTOFMEMORY
;
4609 TRACE("(%p) created object %p\n", This
, object
);
4610 object
->wineD3DDevice
= This
;
4611 /** FIXME: object->parent = parent; **/
4612 object
->parent
= NULL
;
4613 object
->blockType
= WINED3DSBT_RECORDED
;
4615 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4617 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4618 list_init(&object
->lightMap
[i
]);
4621 temp_result
= allocate_shader_constants(object
);
4622 if (WINED3D_OK
!= temp_result
)
4625 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4626 This
->updateStateBlock
= object
;
4627 This
->isRecordingState
= TRUE
;
4629 TRACE("(%p) recording stateblock %p\n",This
, object
);
4633 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4634 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4636 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4638 if (!This
->isRecordingState
) {
4639 FIXME("(%p) not recording! returning error\n", This
);
4640 *ppStateBlock
= NULL
;
4641 return WINED3DERR_INVALIDCALL
;
4644 for(i
= 1; i
<= WINEHIGHEST_RENDER_STATE
; i
++) {
4645 if(object
->changed
.renderState
[i
]) {
4646 object
->contained_render_states
[object
->num_contained_render_states
] = i
;
4647 object
->num_contained_render_states
++;
4650 for(i
= 1; i
<= HIGHEST_TRANSFORMSTATE
; i
++) {
4651 if(object
->changed
.transform
[i
]) {
4652 object
->contained_transform_states
[object
->num_contained_transform_states
] = i
;
4653 object
->num_contained_transform_states
++;
4656 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
4657 if(object
->changed
.vertexShaderConstantsF
[i
]) {
4658 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
4659 object
->num_contained_vs_consts_f
++;
4662 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4663 if(object
->changed
.vertexShaderConstantsI
[i
]) {
4664 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
4665 object
->num_contained_vs_consts_i
++;
4668 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4669 if(object
->changed
.vertexShaderConstantsB
[i
]) {
4670 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
4671 object
->num_contained_vs_consts_b
++;
4674 for(i
= 0; i
< MAX_CONST_I
; i
++) {
4675 if(object
->changed
.pixelShaderConstantsI
[i
]) {
4676 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
4677 object
->num_contained_ps_consts_i
++;
4680 for(i
= 0; i
< MAX_CONST_B
; i
++) {
4681 if(object
->changed
.pixelShaderConstantsB
[i
]) {
4682 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
4683 object
->num_contained_ps_consts_b
++;
4686 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
4687 for(j
= 1; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; j
++) {
4688 if(object
->changed
.textureState
[i
][j
]) {
4689 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
4690 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
4691 object
->num_contained_tss_states
++;
4695 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
4696 for (j
= 1; j
< WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
4697 if(object
->changed
.samplerState
[i
][j
]) {
4698 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
4699 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
4700 object
->num_contained_sampler_states
++;
4705 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4706 This
->isRecordingState
= FALSE
;
4707 This
->updateStateBlock
= This
->stateBlock
;
4708 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4709 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4710 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4715 * Scene related functions
4717 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4718 /* At the moment we have no need for any functionality at the beginning
4720 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4721 TRACE("(%p)\n", This
);
4724 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4725 return WINED3DERR_INVALIDCALL
;
4727 This
->inScene
= TRUE
;
4731 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4732 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4733 TRACE("(%p)\n", This
);
4735 if(!This
->inScene
) {
4736 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4737 return WINED3DERR_INVALIDCALL
;
4740 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4741 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4744 checkGLcall("glFlush");
4747 This
->inScene
= FALSE
;
4751 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4752 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4753 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4754 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4755 IWineD3DSwapChain
*swapChain
= NULL
;
4757 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4759 TRACE("(%p) Presenting the frame\n", This
);
4761 for(i
= 0 ; i
< swapchains
; i
++) {
4763 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4764 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4765 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4766 IWineD3DSwapChain_Release(swapChain
);
4772 /* Not called from the VTable (internal subroutine) */
4773 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4774 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4775 float Z
, DWORD Stencil
) {
4776 GLbitfield glMask
= 0;
4778 WINED3DRECT curRect
;
4780 WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4781 UINT drawable_width
, drawable_height
;
4783 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4784 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4785 * for the cleared parts, and the untouched parts.
4787 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4788 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4789 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4790 * checking all this if the dest surface is in the drawable anyway.
4792 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4794 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4795 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
4796 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4799 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4800 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4801 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
4802 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
4803 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4806 if(Count
> 0 && pRects
&& (
4807 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4808 pRects
[0].x2
< target
->currentDesc
.Width
||
4809 pRects
[0].y2
< target
->currentDesc
.Height
)) {
4810 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4817 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
4819 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
4822 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4823 apply_fbo_state((IWineD3DDevice
*) This
);
4826 /* Only set the values up once, as they are not changing */
4827 if (Flags
& WINED3DCLEAR_STENCIL
) {
4828 glClearStencil(Stencil
);
4829 checkGLcall("glClearStencil");
4830 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4831 glStencilMask(0xFFFFFFFF);
4834 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4835 glDepthMask(GL_TRUE
);
4837 checkGLcall("glClearDepth");
4838 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4839 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4842 if (Flags
& WINED3DCLEAR_TARGET
) {
4843 TRACE("Clearing screen with glClear to color %x\n", Color
);
4844 glClearColor(D3DCOLOR_R(Color
),
4848 checkGLcall("glClearColor");
4850 /* Clear ALL colors! */
4851 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4852 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4855 vp_rect
.left
= vp
->X
;
4856 vp_rect
.top
= vp
->Y
;
4857 vp_rect
.right
= vp
->X
+ vp
->Width
;
4858 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
4859 if (!(Count
> 0 && pRects
)) {
4860 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4861 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
4863 if(This
->render_offscreen
) {
4864 glScissor(vp_rect
.left
, vp_rect
.top
,
4865 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4867 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
4868 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4870 checkGLcall("glScissor");
4872 checkGLcall("glClear");
4874 /* Now process each rect in turn */
4875 for (i
= 0; i
< Count
; i
++) {
4876 /* Note gl uses lower left, width/height */
4877 IntersectRect((RECT
*) &curRect
, &vp_rect
, (RECT
*) &pRects
[i
]);
4878 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4879 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
4881 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
4882 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
4883 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
4884 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4886 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4887 * The rectangle is not cleared, no error is returned, but further rectanlges are
4888 * still cleared if they are valid
4890 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
4891 TRACE("Rectangle with negative dimensions, ignoring\n");
4895 if(This
->render_offscreen
) {
4896 glScissor(curRect
.x1
, curRect
.y1
,
4897 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4899 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
4900 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4902 checkGLcall("glScissor");
4905 checkGLcall("glClear");
4909 /* Restore the old values (why..?) */
4910 if (Flags
& WINED3DCLEAR_STENCIL
) {
4911 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4913 if (Flags
& WINED3DCLEAR_TARGET
) {
4914 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4915 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4916 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4917 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4918 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4920 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4921 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4923 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
4924 /* TODO: Move the fbo logic into ModifyLocation() */
4925 if(This
->render_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4926 target
->Flags
|= SFLAG_INTEXTURE
;
4934 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4935 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4936 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4937 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4939 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4940 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4942 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4943 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4944 /* TODO: What about depth stencil buffers without stencil bits? */
4945 return WINED3DERR_INVALIDCALL
;
4948 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4954 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4955 UINT PrimitiveCount
) {
4957 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4959 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4960 debug_d3dprimitivetype(PrimitiveType
),
4961 StartVertex
, PrimitiveCount
);
4963 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4964 if(This
->stateBlock
->streamIsUP
) {
4965 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4966 This
->stateBlock
->streamIsUP
= FALSE
;
4969 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4970 This
->stateBlock
->loadBaseVertexIndex
= 0;
4971 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4973 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4974 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4975 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4979 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4980 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4981 WINED3DPRIMITIVETYPE PrimitiveType
,
4982 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4984 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4986 IWineD3DIndexBuffer
*pIB
;
4987 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4990 pIB
= This
->stateBlock
->pIndexData
;
4992 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4993 * without an index buffer set. (The first time at least...)
4994 * D3D8 simply dies, but I doubt it can do much harm to return
4995 * D3DERR_INVALIDCALL there as well. */
4996 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4997 return WINED3DERR_INVALIDCALL
;
5000 if(This
->stateBlock
->streamIsUP
) {
5001 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5002 This
->stateBlock
->streamIsUP
= FALSE
;
5004 vbo
= ((IWineD3DIndexBufferImpl
*) pIB
)->vbo
;
5006 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
5007 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5008 minIndex
, NumVertices
, startIndex
, primCount
);
5010 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
5011 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
5017 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5018 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5019 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5022 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
5023 idxStride
, vbo
? NULL
: ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5028 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5029 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
5030 UINT VertexStreamZeroStride
) {
5031 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5032 IWineD3DVertexBuffer
*vb
;
5034 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
5035 debug_d3dprimitivetype(PrimitiveType
),
5036 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5038 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5039 vb
= This
->stateBlock
->streamSource
[0];
5040 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5041 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5042 This
->stateBlock
->streamOffset
[0] = 0;
5043 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5044 This
->stateBlock
->streamIsUP
= TRUE
;
5045 This
->stateBlock
->loadBaseVertexIndex
= 0;
5047 /* TODO: Only mark dirty if drawing from a different UP address */
5048 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5050 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
5051 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5053 /* MSDN specifies stream zero settings must be set to NULL */
5054 This
->stateBlock
->streamStride
[0] = 0;
5055 This
->stateBlock
->streamSource
[0] = NULL
;
5057 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5058 * the new stream sources or use UP drawing again
5063 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
5064 UINT MinVertexIndex
, UINT NumVertices
,
5065 UINT PrimitiveCount
, CONST
void* pIndexData
,
5066 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
5067 UINT VertexStreamZeroStride
) {
5069 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5070 IWineD3DVertexBuffer
*vb
;
5071 IWineD3DIndexBuffer
*ib
;
5073 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5074 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
5075 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
5076 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5078 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
5084 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5085 vb
= This
->stateBlock
->streamSource
[0];
5086 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
5087 if(vb
) IWineD3DVertexBuffer_Release(vb
);
5088 This
->stateBlock
->streamIsUP
= TRUE
;
5089 This
->stateBlock
->streamOffset
[0] = 0;
5090 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5092 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5093 This
->stateBlock
->baseVertexIndex
= 0;
5094 This
->stateBlock
->loadBaseVertexIndex
= 0;
5095 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5096 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5097 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5099 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
5101 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5102 This
->stateBlock
->streamSource
[0] = NULL
;
5103 This
->stateBlock
->streamStride
[0] = 0;
5104 ib
= This
->stateBlock
->pIndexData
;
5106 IWineD3DIndexBuffer_Release(ib
);
5107 This
->stateBlock
->pIndexData
= NULL
;
5109 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5110 * SetStreamSource to specify a vertex buffer
5116 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
5117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5119 /* Mark the state dirty until we have nicer tracking
5120 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5123 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5124 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5125 This
->stateBlock
->baseVertexIndex
= 0;
5126 This
->up_strided
= DrawPrimStrideData
;
5127 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
5128 This
->up_strided
= NULL
;
5132 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
, UINT NumVertices
, CONST
void *pIndexData
, WINED3DFORMAT IndexDataFormat
) {
5133 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5134 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_INDEX32
? 4 : 2);
5136 /* Mark the state dirty until we have nicer tracking
5137 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5140 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5141 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5142 This
->stateBlock
->streamIsUP
= TRUE
;
5143 This
->stateBlock
->baseVertexIndex
= 0;
5144 This
->up_strided
= DrawPrimStrideData
;
5145 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize
, pIndexData
, 0 /* minindex */);
5146 This
->up_strided
= NULL
;
5150 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5151 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5152 * not callable by the app directly no parameter validation checks are needed here.
5154 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5155 WINED3DLOCKED_BOX src
;
5156 WINED3DLOCKED_BOX dst
;
5158 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5160 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5161 * dirtification to improve loading performance.
5163 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5164 if(FAILED(hr
)) return hr
;
5165 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5167 IWineD3DVolume_UnlockBox(pSourceVolume
);
5171 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5173 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5175 IWineD3DVolume_UnlockBox(pSourceVolume
);
5177 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5182 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5183 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5184 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5185 HRESULT hr
= WINED3D_OK
;
5186 WINED3DRESOURCETYPE sourceType
;
5187 WINED3DRESOURCETYPE destinationType
;
5190 /* TODO: think about moving the code into IWineD3DBaseTexture */
5192 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5194 /* verify that the source and destination textures aren't NULL */
5195 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5196 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5197 This
, pSourceTexture
, pDestinationTexture
);
5198 hr
= WINED3DERR_INVALIDCALL
;
5201 if (pSourceTexture
== pDestinationTexture
) {
5202 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5203 This
, pSourceTexture
, pDestinationTexture
);
5204 hr
= WINED3DERR_INVALIDCALL
;
5206 /* Verify that the source and destination textures are the same type */
5207 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5208 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5210 if (sourceType
!= destinationType
) {
5211 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5213 hr
= WINED3DERR_INVALIDCALL
;
5216 /* check that both textures have the identical numbers of levels */
5217 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5218 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5219 hr
= WINED3DERR_INVALIDCALL
;
5222 if (WINED3D_OK
== hr
) {
5224 /* Make sure that the destination texture is loaded */
5225 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
5227 /* Update every surface level of the texture */
5228 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5230 switch (sourceType
) {
5231 case WINED3DRTYPE_TEXTURE
:
5233 IWineD3DSurface
*srcSurface
;
5234 IWineD3DSurface
*destSurface
;
5236 for (i
= 0 ; i
< levels
; ++i
) {
5237 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5238 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5239 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5240 IWineD3DSurface_Release(srcSurface
);
5241 IWineD3DSurface_Release(destSurface
);
5242 if (WINED3D_OK
!= hr
) {
5243 WARN("(%p) : Call to update surface failed\n", This
);
5249 case WINED3DRTYPE_CUBETEXTURE
:
5251 IWineD3DSurface
*srcSurface
;
5252 IWineD3DSurface
*destSurface
;
5253 WINED3DCUBEMAP_FACES faceType
;
5255 for (i
= 0 ; i
< levels
; ++i
) {
5256 /* Update each cube face */
5257 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5258 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5259 if (WINED3D_OK
!= hr
) {
5260 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5262 TRACE("Got srcSurface %p\n", srcSurface
);
5264 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5265 if (WINED3D_OK
!= hr
) {
5266 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5268 TRACE("Got desrSurface %p\n", destSurface
);
5270 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5271 IWineD3DSurface_Release(srcSurface
);
5272 IWineD3DSurface_Release(destSurface
);
5273 if (WINED3D_OK
!= hr
) {
5274 WARN("(%p) : Call to update surface failed\n", This
);
5282 case WINED3DRTYPE_VOLUMETEXTURE
:
5284 IWineD3DVolume
*srcVolume
= NULL
;
5285 IWineD3DVolume
*destVolume
= NULL
;
5287 for (i
= 0 ; i
< levels
; ++i
) {
5288 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5289 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5290 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5291 IWineD3DVolume_Release(srcVolume
);
5292 IWineD3DVolume_Release(destVolume
);
5293 if (WINED3D_OK
!= hr
) {
5294 WARN("(%p) : Call to update volume failed\n", This
);
5302 FIXME("(%p) : Unsupported source and destination type\n", This
);
5303 hr
= WINED3DERR_INVALIDCALL
;
5310 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5311 IWineD3DSwapChain
*swapChain
;
5313 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5314 if(hr
== WINED3D_OK
) {
5315 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5316 IWineD3DSwapChain_Release(swapChain
);
5321 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5322 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5323 /* return a sensible default */
5325 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5326 FIXME("(%p) : stub\n", This
);
5330 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5333 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5334 if (PaletteNumber
>= MAX_PALETTES
) {
5335 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5336 return WINED3DERR_INVALIDCALL
;
5338 for (j
= 0; j
< 256; ++j
) {
5339 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5340 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5341 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5342 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5344 TRACE("(%p) : returning\n", This
);
5348 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5349 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5351 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5352 if (PaletteNumber
>= MAX_PALETTES
) {
5353 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5354 return WINED3DERR_INVALIDCALL
;
5356 for (j
= 0; j
< 256; ++j
) {
5357 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5358 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5359 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5360 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5362 TRACE("(%p) : returning\n", This
);
5366 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5367 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5368 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5369 if (PaletteNumber
>= MAX_PALETTES
) {
5370 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5371 return WINED3DERR_INVALIDCALL
;
5373 /*TODO: stateblocks */
5374 This
->currentPalette
= PaletteNumber
;
5375 TRACE("(%p) : returning\n", This
);
5379 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5380 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5381 if (PaletteNumber
== NULL
) {
5382 WARN("(%p) : returning Invalid Call\n", This
);
5383 return WINED3DERR_INVALIDCALL
;
5385 /*TODO: stateblocks */
5386 *PaletteNumber
= This
->currentPalette
;
5387 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5391 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5392 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5393 static BOOL showFixmes
= TRUE
;
5395 FIXME("(%p) : stub\n", This
);
5399 This
->softwareVertexProcessing
= bSoftware
;
5404 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5405 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5406 static BOOL showFixmes
= TRUE
;
5408 FIXME("(%p) : stub\n", This
);
5411 return This
->softwareVertexProcessing
;
5415 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5416 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5417 IWineD3DSwapChain
*swapChain
;
5420 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5422 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5423 if(hr
== WINED3D_OK
){
5424 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5425 IWineD3DSwapChain_Release(swapChain
);
5427 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5433 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5434 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5435 static BOOL showfixmes
= TRUE
;
5436 if(nSegments
!= 0.0f
) {
5438 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5445 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5446 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5447 static BOOL showfixmes
= TRUE
;
5449 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5455 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5456 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5457 /** TODO: remove casts to IWineD3DSurfaceImpl
5458 * NOTE: move code to surface to accomplish this
5459 ****************************************/
5460 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5461 int srcWidth
, srcHeight
;
5462 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5463 WINED3DFORMAT destFormat
, srcFormat
;
5465 int srcLeft
, destLeft
, destTop
;
5466 WINED3DPOOL srcPool
, destPool
;
5468 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5469 glDescriptor
*glDescription
= NULL
;
5472 CONVERT_TYPES convert
= NO_CONVERSION
;
5474 WINED3DSURFACE_DESC winedesc
;
5476 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5477 memset(&winedesc
, 0, sizeof(winedesc
));
5478 winedesc
.Width
= &srcSurfaceWidth
;
5479 winedesc
.Height
= &srcSurfaceHeight
;
5480 winedesc
.Pool
= &srcPool
;
5481 winedesc
.Format
= &srcFormat
;
5483 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5485 winedesc
.Width
= &destSurfaceWidth
;
5486 winedesc
.Height
= &destSurfaceHeight
;
5487 winedesc
.Pool
= &destPool
;
5488 winedesc
.Format
= &destFormat
;
5489 winedesc
.Size
= &destSize
;
5491 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5493 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5494 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5495 return WINED3DERR_INVALIDCALL
;
5498 /* This call loads the opengl surface directly, instead of copying the surface to the
5499 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5500 * copy in sysmem and use regular surface loading.
5502 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
5503 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5504 if(convert
!= NO_CONVERSION
) {
5505 return IWineD3DSurface_BltFast(pDestinationSurface
,
5506 pDestPoint
? pDestPoint
->x
: 0,
5507 pDestPoint
? pDestPoint
->y
: 0,
5508 pSourceSurface
, (RECT
*) pSourceRect
, 0);
5511 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5512 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5513 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5515 /* Get the update surface description */
5516 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5519 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5523 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
5524 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5525 checkGLcall("glActiveTextureARB");
5528 /* Make sure the surface is loaded and up to date */
5529 IWineD3DSurface_PreLoad(pDestinationSurface
);
5531 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5533 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5534 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5535 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5536 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5537 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5538 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5541 /* This function doesn't support compressed textures
5542 the pitch is just bytesPerPixel * width */
5543 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5544 rowoffset
= srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5545 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5546 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5548 /* TODO DXT formats */
5550 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5551 offset
+= pSourceRect
->top
* srcSurfaceWidth
* pSrcSurface
->bytesPerPixel
;
5553 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5555 ,glDescription
->level
5560 ,glDescription
->glFormat
5561 ,glDescription
->glType
5562 ,IWineD3DSurface_GetData(pSourceSurface
)
5566 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5568 /* need to lock the surface to get the data */
5569 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5572 /* TODO: Cube and volume support */
5574 /* not a whole row so we have to do it a line at a time */
5577 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5578 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5580 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5582 glTexSubImage2D(glDescription
->target
5583 ,glDescription
->level
5588 ,glDescription
->glFormat
5589 ,glDescription
->glType
5590 ,data
/* could be quicker using */
5595 } else { /* Full width, so just write out the whole texture */
5597 if (WINED3DFMT_DXT1
== destFormat
||
5598 WINED3DFMT_DXT2
== destFormat
||
5599 WINED3DFMT_DXT3
== destFormat
||
5600 WINED3DFMT_DXT4
== destFormat
||
5601 WINED3DFMT_DXT5
== destFormat
) {
5602 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5603 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5604 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5605 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5606 } if (destFormat
!= srcFormat
) {
5607 FIXME("Updating mixed format compressed texture is not curretly support\n");
5609 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5610 glDescription
->level
,
5611 glDescription
->glFormatInternal
,
5616 IWineD3DSurface_GetData(pSourceSurface
));
5619 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5624 glTexSubImage2D(glDescription
->target
5625 ,glDescription
->level
5630 ,glDescription
->glFormat
5631 ,glDescription
->glType
5632 ,IWineD3DSurface_GetData(pSourceSurface
)
5636 checkGLcall("glTexSubImage2D");
5640 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5641 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
5646 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5647 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5648 struct WineD3DRectPatch
*patch
;
5652 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5654 if(!(Handle
|| pRectPatchInfo
)) {
5655 /* TODO: Write a test for the return value, thus the FIXME */
5656 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5657 return WINED3DERR_INVALIDCALL
;
5661 i
= PATCHMAP_HASHFUNC(Handle
);
5663 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5664 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5665 if(patch
->Handle
== Handle
) {
5672 TRACE("Patch does not exist. Creating a new one\n");
5673 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5674 patch
->Handle
= Handle
;
5675 list_add_head(&This
->patches
[i
], &patch
->entry
);
5677 TRACE("Found existing patch %p\n", patch
);
5680 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5681 * attributes we have to tesselate, read back, and draw. This needs a patch
5682 * management structure instance. Create one.
5684 * A possible improvement is to check if a vertex shader is used, and if not directly
5687 FIXME("Drawing an uncached patch. This is slow\n");
5688 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5691 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5692 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5693 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5695 TRACE("Tesselation density or patch info changed, retesselating\n");
5697 if(pRectPatchInfo
) {
5698 memcpy(&patch
->RectPatchInfo
, pRectPatchInfo
, sizeof(*pRectPatchInfo
));
5700 patch
->numSegs
[0] = pNumSegs
[0];
5701 patch
->numSegs
[1] = pNumSegs
[1];
5702 patch
->numSegs
[2] = pNumSegs
[2];
5703 patch
->numSegs
[3] = pNumSegs
[3];
5705 hr
= tesselate_rectpatch(This
, patch
);
5707 WARN("Patch tesselation failed\n");
5709 /* Do not release the handle to store the params of the patch */
5711 HeapFree(GetProcessHeap(), 0, patch
);
5717 This
->currentPatch
= patch
;
5718 IWineD3DDevice_DrawPrimitiveStrided(iface
, WINED3DPT_TRIANGLELIST
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2, &patch
->strided
);
5719 This
->currentPatch
= NULL
;
5721 /* Destroy uncached patches */
5723 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5724 HeapFree(GetProcessHeap(), 0, patch
);
5729 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5730 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5732 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5733 FIXME("(%p) : Stub\n", This
);
5737 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5738 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5740 struct WineD3DRectPatch
*patch
;
5742 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5744 i
= PATCHMAP_HASHFUNC(Handle
);
5745 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5746 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5747 if(patch
->Handle
== Handle
) {
5748 TRACE("Deleting patch %p\n", patch
);
5749 list_remove(&patch
->entry
);
5750 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5751 HeapFree(GetProcessHeap(), 0, patch
);
5756 /* TODO: Write a test for the return value */
5757 FIXME("Attempt to destroy nonexistent patch\n");
5758 return WINED3DERR_INVALIDCALL
;
5761 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5763 IWineD3DSwapChain
*swapchain
;
5765 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5766 if (SUCCEEDED(hr
)) {
5767 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5774 static void bind_fbo(IWineD3DDevice
*iface
, GLenum target
, GLuint
*fbo
) {
5775 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5778 GL_EXTCALL(glGenFramebuffersEXT(1, fbo
));
5779 checkGLcall("glGenFramebuffersEXT()");
5781 GL_EXTCALL(glBindFramebufferEXT(target
, *fbo
));
5782 checkGLcall("glBindFramebuffer()");
5785 static void attach_surface_fbo(IWineD3DDeviceImpl
*This
, GLenum fbo_target
, DWORD idx
, IWineD3DSurface
*surface
) {
5786 const IWineD3DSurfaceImpl
*surface_impl
= (IWineD3DSurfaceImpl
*)surface
;
5787 IWineD3DBaseTextureImpl
*texture_impl
;
5788 GLenum texttarget
, target
;
5791 texttarget
= surface_impl
->glDescription
.target
;
5792 if(texttarget
== GL_TEXTURE_2D
) {
5793 target
= GL_TEXTURE_2D
;
5794 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5795 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
5796 target
= GL_TEXTURE_RECTANGLE_ARB
;
5797 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5799 target
= GL_TEXTURE_CUBE_MAP_ARB
;
5800 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5803 IWineD3DSurface_PreLoad(surface
);
5805 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5806 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5807 glBindTexture(target
, old_binding
);
5809 /* Update base texture states array */
5810 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
5811 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
5812 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
5813 if (texture_impl
->baseTexture
.bindCount
) {
5814 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
5817 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
5820 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
,
5821 surface_impl
->glDescription
.textureName
, surface_impl
->glDescription
.level
));
5823 checkGLcall("attach_surface_fbo");
5826 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
, CONST WINED3DRECT
*rect
, WINED3DCOLOR color
) {
5827 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5828 IWineD3DSwapChain
*swapchain
;
5830 swapchain
= get_swapchain(surface
);
5834 TRACE("Surface %p is onscreen\n", surface
);
5836 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5837 buffer
= surface_get_gl_buffer(surface
, swapchain
);
5838 glDrawBuffer(buffer
);
5839 checkGLcall("glDrawBuffer()");
5841 TRACE("Surface %p is offscreen\n", surface
);
5842 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
5843 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
5847 glEnable(GL_SCISSOR_TEST
);
5849 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5851 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5852 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5854 checkGLcall("glScissor");
5856 glDisable(GL_SCISSOR_TEST
);
5858 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5860 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5861 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5863 glClearColor(D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
));
5864 glClear(GL_COLOR_BUFFER_BIT
);
5865 checkGLcall("glClear");
5867 if (This
->render_offscreen
) {
5868 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
5870 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5871 checkGLcall("glBindFramebuffer()");
5874 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
5875 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
5876 glDrawBuffer(GL_BACK
);
5877 checkGLcall("glDrawBuffer()");
5881 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5882 unsigned int r
, g
, b
, a
;
5885 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
5886 destfmt
== WINED3DFMT_R8G8B8
)
5889 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5891 a
= (color
& 0xff000000) >> 24;
5892 r
= (color
& 0x00ff0000) >> 16;
5893 g
= (color
& 0x0000ff00) >> 8;
5894 b
= (color
& 0x000000ff) >> 0;
5898 case WINED3DFMT_R5G6B5
:
5899 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5906 TRACE("Returning %08x\n", ret
);
5909 case WINED3DFMT_X1R5G5B5
:
5910 case WINED3DFMT_A1R5G5B5
:
5919 TRACE("Returning %08x\n", ret
);
5923 TRACE("Returning %08x\n", a
);
5926 case WINED3DFMT_X4R4G4B4
:
5927 case WINED3DFMT_A4R4G4B4
:
5936 TRACE("Returning %08x\n", ret
);
5939 case WINED3DFMT_R3G3B2
:
5946 TRACE("Returning %08x\n", ret
);
5949 case WINED3DFMT_X8B8G8R8
:
5950 case WINED3DFMT_A8B8G8R8
:
5955 TRACE("Returning %08x\n", ret
);
5958 case WINED3DFMT_A2R10G10B10
:
5960 r
= (r
* 1024) / 256;
5961 g
= (g
* 1024) / 256;
5962 b
= (b
* 1024) / 256;
5967 TRACE("Returning %08x\n", ret
);
5970 case WINED3DFMT_A2B10G10R10
:
5972 r
= (r
* 1024) / 256;
5973 g
= (g
* 1024) / 256;
5974 b
= (b
* 1024) / 256;
5979 TRACE("Returning %08x\n", ret
);
5983 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5988 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5989 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5990 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5992 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
5994 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5995 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5996 return WINED3DERR_INVALIDCALL
;
5999 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6000 color_fill_fbo(iface
, pSurface
, pRect
, color
);
6003 /* Just forward this to the DirectDraw blitting engine */
6004 memset(&BltFx
, 0, sizeof(BltFx
));
6005 BltFx
.dwSize
= sizeof(BltFx
);
6006 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format
);
6007 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6011 /* rendertarget and deptth stencil functions */
6012 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6013 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6015 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6016 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6017 return WINED3DERR_INVALIDCALL
;
6020 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6021 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6022 /* Note inc ref on returned surface */
6023 if(*ppRenderTarget
!= NULL
)
6024 IWineD3DSurface_AddRef(*ppRenderTarget
);
6028 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6029 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6030 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6031 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6032 IWineD3DSwapChainImpl
*Swapchain
;
6035 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6037 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6038 if(hr
!= WINED3D_OK
) {
6039 ERR("Can't get the swapchain\n");
6043 /* Make sure to release the swapchain */
6044 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6046 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6047 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6048 return WINED3DERR_INVALIDCALL
;
6050 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6051 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6052 return WINED3DERR_INVALIDCALL
;
6055 if(Swapchain
->frontBuffer
!= Front
) {
6056 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6058 if(Swapchain
->frontBuffer
)
6059 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6060 Swapchain
->frontBuffer
= Front
;
6062 if(Swapchain
->frontBuffer
) {
6063 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6067 if(Back
&& !Swapchain
->backBuffer
) {
6068 /* We need memory for the back buffer array - only one back buffer this way */
6069 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6070 if(!Swapchain
->backBuffer
) {
6071 ERR("Out of memory\n");
6072 return E_OUTOFMEMORY
;
6076 if(Swapchain
->backBuffer
[0] != Back
) {
6077 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6079 /* What to do about the context here in the case of multithreading? Not sure.
6080 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6083 if(!Swapchain
->backBuffer
[0]) {
6084 /* GL was told to draw to the front buffer at creation,
6087 glDrawBuffer(GL_BACK
);
6088 checkGLcall("glDrawBuffer(GL_BACK)");
6089 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6090 Swapchain
->presentParms
.BackBufferCount
= 1;
6092 /* That makes problems - disable for now */
6093 /* glDrawBuffer(GL_FRONT); */
6094 checkGLcall("glDrawBuffer(GL_FRONT)");
6095 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6096 Swapchain
->presentParms
.BackBufferCount
= 0;
6100 if(Swapchain
->backBuffer
[0])
6101 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6102 Swapchain
->backBuffer
[0] = Back
;
6104 if(Swapchain
->backBuffer
[0]) {
6105 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6107 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6108 Swapchain
->backBuffer
= NULL
;
6116 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6118 *ppZStencilSurface
= This
->stencilBufferTarget
;
6119 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6121 if(*ppZStencilSurface
!= NULL
) {
6122 /* Note inc ref on returned surface */
6123 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6126 return WINED3DERR_NOTFOUND
;
6130 /* TODO: Handle stencil attachments */
6131 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
6132 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6133 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
6135 TRACE("Set depth stencil to %p\n", depth_stencil
);
6137 if (depth_stencil_impl
) {
6138 if (depth_stencil_impl
->current_renderbuffer
) {
6139 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, depth_stencil_impl
->current_renderbuffer
->id
));
6140 checkGLcall("glFramebufferRenderbufferEXT()");
6142 IWineD3DBaseTextureImpl
*texture_impl
;
6143 GLenum texttarget
, target
;
6144 GLint old_binding
= 0;
6146 texttarget
= depth_stencil_impl
->glDescription
.target
;
6147 if(texttarget
== GL_TEXTURE_2D
) {
6148 target
= GL_TEXTURE_2D
;
6149 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
6150 } else if(texttarget
== GL_TEXTURE_RECTANGLE_ARB
) {
6151 target
= GL_TEXTURE_RECTANGLE_ARB
;
6152 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
6154 target
= GL_TEXTURE_CUBE_MAP_ARB
;
6155 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
6158 IWineD3DSurface_PreLoad(depth_stencil
);
6160 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
6161 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
6162 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
6163 glBindTexture(target
, old_binding
);
6165 /* Update base texture states array */
6166 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil
, &IID_IWineD3DBaseTexture
, (void **)&texture_impl
))) {
6167 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
6168 texture_impl
->baseTexture
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
6169 if (texture_impl
->baseTexture
.bindCount
) {
6170 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(texture_impl
->baseTexture
.sampler
));
6173 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*)texture_impl
);
6176 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
,
6177 depth_stencil_impl
->glDescription
.textureName
, depth_stencil_impl
->glDescription
.level
));
6178 checkGLcall("glFramebufferTexture2DEXT()");
6181 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
6182 checkGLcall("glFramebufferTexture2DEXT()");
6186 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
6187 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6188 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
6190 TRACE("Set render target %u to %p\n", idx
, render_target
);
6193 attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, idx
, render_target
);
6194 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
6196 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
6197 checkGLcall("glFramebufferTexture2DEXT()");
6199 This
->draw_buffers
[idx
] = GL_NONE
;
6203 static void check_fbo_status(IWineD3DDevice
*iface
) {
6204 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6207 status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
6208 if (status
== GL_FRAMEBUFFER_COMPLETE_EXT
) {
6209 TRACE("FBO complete\n");
6211 IWineD3DSurfaceImpl
*attachment
;
6213 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status
), status
);
6215 /* Dump the FBO attachments */
6216 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6217 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_color_attachments
[i
];
6219 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i
, attachment
, debug_d3dformat(attachment
->resource
.format
),
6220 attachment
->pow2Width
, attachment
->pow2Height
);
6223 attachment
= (IWineD3DSurfaceImpl
*)This
->fbo_depth_attachment
;
6225 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment
, debug_d3dformat(attachment
->resource
.format
),
6226 attachment
->pow2Width
, attachment
->pow2Height
);
6231 static BOOL
depth_mismatch_fbo(IWineD3DDevice
*iface
) {
6232 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6233 IWineD3DSurfaceImpl
*rt_impl
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
6234 IWineD3DSurfaceImpl
*ds_impl
= (IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
;
6236 if (!ds_impl
) return FALSE
;
6238 if (ds_impl
->current_renderbuffer
) {
6239 return (rt_impl
->pow2Width
!= ds_impl
->current_renderbuffer
->width
||
6240 rt_impl
->pow2Height
!= ds_impl
->current_renderbuffer
->height
);
6243 return (rt_impl
->pow2Width
!= ds_impl
->pow2Width
||
6244 rt_impl
->pow2Height
!= ds_impl
->pow2Height
);
6247 void apply_fbo_state(IWineD3DDevice
*iface
) {
6248 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6251 if (This
->render_offscreen
) {
6252 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6254 /* Apply render targets */
6255 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
6256 IWineD3DSurface
*render_target
= This
->render_targets
[i
];
6257 if (This
->fbo_color_attachments
[i
] != render_target
) {
6258 set_render_target_fbo(iface
, i
, render_target
);
6259 This
->fbo_color_attachments
[i
] = render_target
;
6263 /* Apply depth targets */
6264 if (This
->fbo_depth_attachment
!= This
->stencilBufferTarget
|| depth_mismatch_fbo(iface
)) {
6265 unsigned int w
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Width
;
6266 unsigned int h
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->pow2Height
;
6268 if (This
->stencilBufferTarget
) {
6269 surface_set_compatible_renderbuffer(This
->stencilBufferTarget
, w
, h
);
6271 set_depth_stencil_fbo(iface
, This
->stencilBufferTarget
);
6272 This
->fbo_depth_attachment
= This
->stencilBufferTarget
;
6275 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
6276 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
6277 checkGLcall("glDrawBuffers()");
6279 glDrawBuffer(This
->draw_buffers
[0]);
6280 checkGLcall("glDrawBuffer()");
6283 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6286 check_fbo_status(iface
);
6289 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6290 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
) {
6291 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6292 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6293 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6296 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6297 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6298 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6299 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6302 case WINED3DTEXF_LINEAR
:
6303 gl_filter
= GL_LINEAR
;
6307 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6308 case WINED3DTEXF_NONE
:
6309 case WINED3DTEXF_POINT
:
6310 gl_filter
= GL_NEAREST
;
6314 /* Attach src surface to src fbo */
6315 src_swapchain
= get_swapchain(src_surface
);
6316 if (src_swapchain
) {
6319 TRACE("Source surface %p is onscreen\n", src_surface
);
6320 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6321 /* Make sure the drawable is up to date. In the offscreen case
6322 * attach_surface_fbo() implicitly takes care of this. */
6323 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6326 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6327 buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6328 glReadBuffer(buffer
);
6329 checkGLcall("glReadBuffer()");
6331 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6332 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6334 TRACE("Source surface %p is offscreen\n", src_surface
);
6336 bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->src_fbo
);
6337 attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6338 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6339 checkGLcall("glReadBuffer()");
6343 /* Attach dst surface to dst fbo */
6344 dst_swapchain
= get_swapchain(dst_surface
);
6345 if (dst_swapchain
) {
6348 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6349 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6350 /* Make sure the drawable is up to date. In the offscreen case
6351 * attach_surface_fbo() implicitly takes care of this. */
6352 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6355 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6356 buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6357 glDrawBuffer(buffer
);
6358 checkGLcall("glDrawBuffer()");
6360 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6361 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6363 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6365 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6366 if(!src_swapchain
) {
6367 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6371 bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->dst_fbo
);
6372 attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
6373 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6374 checkGLcall("glDrawBuffer()");
6376 glDisable(GL_SCISSOR_TEST
);
6377 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6380 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6381 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
6382 checkGLcall("glBlitFramebuffer()");
6384 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6385 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
6386 checkGLcall("glBlitFramebuffer()");
6389 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6391 if (This
->render_offscreen
) {
6392 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
6394 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6395 checkGLcall("glBindFramebuffer()");
6398 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6399 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6400 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6401 glDrawBuffer(GL_BACK
);
6402 checkGLcall("glDrawBuffer()");
6407 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
6408 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6409 WINED3DVIEWPORT viewport
;
6411 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6413 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6414 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6415 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
6416 return WINED3DERR_INVALIDCALL
;
6419 /* MSDN says that null disables the render target
6420 but a device must always be associated with a render target
6421 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6423 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6426 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6427 FIXME("Trying to set render target 0 to NULL\n");
6428 return WINED3DERR_INVALIDCALL
;
6430 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6431 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
);
6432 return WINED3DERR_INVALIDCALL
;
6435 /* If we are trying to set what we already have, don't bother */
6436 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6437 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6440 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6441 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6442 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6444 /* Render target 0 is special */
6445 if(RenderTargetIndex
== 0) {
6446 /* Finally, reset the viewport as the MSDN states. */
6447 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6448 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6451 viewport
.MaxZ
= 1.0f
;
6452 viewport
.MinZ
= 0.0f
;
6453 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
6454 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6455 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6457 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6459 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6461 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6462 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6464 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6469 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6471 HRESULT hr
= WINED3D_OK
;
6472 IWineD3DSurface
*tmp
;
6474 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6476 if (pNewZStencil
== This
->stencilBufferTarget
) {
6477 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6479 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6480 * depending on the renter target implementation being used.
6481 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6482 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6483 * stencil buffer and incure an extra memory overhead
6484 ******************************************************/
6486 tmp
= This
->stencilBufferTarget
;
6487 This
->stencilBufferTarget
= pNewZStencil
;
6488 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
6489 /* should we be calling the parent or the wined3d surface? */
6490 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6491 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6494 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6495 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6496 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6497 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6498 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6505 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6506 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6507 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6508 /* TODO: the use of Impl is deprecated. */
6509 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6510 WINED3DLOCKED_RECT lockedRect
;
6512 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6514 /* some basic validation checks */
6515 if(This
->cursorTexture
) {
6516 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6518 glDeleteTextures(1, &This
->cursorTexture
);
6520 This
->cursorTexture
= 0;
6523 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6524 This
->haveHardwareCursor
= TRUE
;
6526 This
->haveHardwareCursor
= FALSE
;
6529 WINED3DLOCKED_RECT rect
;
6531 /* MSDN: Cursor must be A8R8G8B8 */
6532 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6533 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6534 return WINED3DERR_INVALIDCALL
;
6537 /* MSDN: Cursor must be smaller than the display mode */
6538 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6539 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6540 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
);
6541 return WINED3DERR_INVALIDCALL
;
6544 if (!This
->haveHardwareCursor
) {
6545 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6547 /* Do not store the surface's pointer because the application may
6548 * release it after setting the cursor image. Windows doesn't
6549 * addref the set surface, so we can't do this either without
6550 * creating circular refcount dependencies. Copy out the gl texture
6553 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6554 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6555 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6557 const GlPixelFormatDesc
*glDesc
;
6558 const StaticPixelFormatDesc
*tableEntry
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
, &glDesc
);
6559 char *mem
, *bits
= (char *)rect
.pBits
;
6560 GLint intfmt
= glDesc
->glInternal
;
6561 GLint format
= glDesc
->glFormat
;
6562 GLint type
= glDesc
->glType
;
6563 INT height
= This
->cursorHeight
;
6564 INT width
= This
->cursorWidth
;
6565 INT bpp
= tableEntry
->bpp
;
6568 /* Reformat the texture memory (pitch and width can be
6570 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6571 for(i
= 0; i
< height
; i
++)
6572 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6573 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6576 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6577 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6578 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6581 /* Make sure that a proper texture unit is selected */
6582 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
6583 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6584 checkGLcall("glActiveTextureARB");
6586 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(0));
6587 /* Create a new cursor texture */
6588 glGenTextures(1, &This
->cursorTexture
);
6589 checkGLcall("glGenTextures");
6590 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6591 checkGLcall("glBindTexture");
6592 /* Copy the bitmap memory into the cursor texture */
6593 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6594 HeapFree(GetProcessHeap(), 0, mem
);
6595 checkGLcall("glTexImage2D");
6597 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
6598 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6599 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6606 FIXME("A cursor texture was not returned.\n");
6607 This
->cursorTexture
= 0;
6612 /* Draw a hardware cursor */
6613 ICONINFO cursorInfo
;
6615 /* Create and clear maskBits because it is not needed for
6616 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6618 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6619 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6620 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6621 WINED3DLOCK_NO_DIRTY_UPDATE
|
6622 WINED3DLOCK_READONLY
6624 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6625 pSur
->currentDesc
.Height
);
6627 cursorInfo
.fIcon
= FALSE
;
6628 cursorInfo
.xHotspot
= XHotSpot
;
6629 cursorInfo
.yHotspot
= YHotSpot
;
6630 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
6631 pSur
->currentDesc
.Height
, 1,
6633 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
6634 pSur
->currentDesc
.Height
, 1,
6635 32, lockedRect
.pBits
);
6636 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6637 /* Create our cursor and clean up. */
6638 cursor
= CreateIconIndirect(&cursorInfo
);
6640 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6641 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6642 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6643 This
->hardwareCursor
= cursor
;
6644 HeapFree(GetProcessHeap(), 0, maskBits
);
6648 This
->xHotSpot
= XHotSpot
;
6649 This
->yHotSpot
= YHotSpot
;
6653 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6654 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6655 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6657 This
->xScreenSpace
= XScreenSpace
;
6658 This
->yScreenSpace
= YScreenSpace
;
6664 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6665 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6666 BOOL oldVisible
= This
->bCursorVisible
;
6669 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6672 * When ShowCursor is first called it should make the cursor appear at the OS's last
6673 * known cursor position. Because of this, some applications just repetitively call
6674 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6677 This
->xScreenSpace
= pt
.x
;
6678 This
->yScreenSpace
= pt
.y
;
6680 if (This
->haveHardwareCursor
) {
6681 This
->bCursorVisible
= bShow
;
6683 SetCursor(This
->hardwareCursor
);
6689 if (This
->cursorTexture
)
6690 This
->bCursorVisible
= bShow
;
6696 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6697 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6698 IWineD3DResourceImpl
*resource
;
6699 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6701 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6702 switch (This
->state
) {
6705 case WINED3DERR_DEVICELOST
:
6707 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6708 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
6709 return WINED3DERR_DEVICENOTRESET
;
6711 return WINED3DERR_DEVICELOST
;
6713 case WINED3DERR_DRIVERINTERNALERROR
:
6714 return WINED3DERR_DRIVERINTERNALERROR
;
6718 return WINED3DERR_DRIVERINTERNALERROR
;
6722 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6723 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6724 /** FIXME: Resource tracking needs to be done,
6725 * The closes we can do to this is set the priorities of all managed textures low
6726 * and then reset them.
6727 ***********************************************************/
6728 FIXME("(%p) : stub\n", This
);
6732 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6733 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
6735 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6736 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6737 /* Release the DC */
6738 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6739 DeleteDC(surface
->hDC
);
6740 /* Release the DIB section */
6741 DeleteObject(surface
->dib
.DIBsection
);
6742 surface
->dib
.bitmap_data
= NULL
;
6743 surface
->resource
.allocatedMemory
= NULL
;
6744 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6746 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6747 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6748 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
6749 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6750 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6752 surface
->pow2Width
= surface
->pow2Height
= 1;
6753 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6754 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6756 if(surface
->glDescription
.textureName
) {
6757 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6759 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6761 surface
->glDescription
.textureName
= 0;
6762 surface
->Flags
&= ~SFLAG_CLIENT
;
6764 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6765 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6766 surface
->Flags
|= SFLAG_NONPOW2
;
6768 surface
->Flags
&= ~SFLAG_NONPOW2
;
6770 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
6771 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6774 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6775 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6776 IWineD3DSwapChainImpl
*swapchain
;
6778 BOOL DisplayModeChanged
= FALSE
;
6779 WINED3DDISPLAYMODE mode
;
6780 TRACE("(%p)\n", This
);
6782 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6784 ERR("Failed to get the first implicit swapchain\n");
6788 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6789 * on an existing gl context, so there's no real need for recreation.
6791 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6793 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6795 TRACE("New params:\n");
6796 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6797 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6798 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6799 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6800 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6801 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6802 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6803 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6804 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6805 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6806 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6807 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6808 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6810 /* No special treatment of these parameters. Just store them */
6811 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6812 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6813 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6814 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6816 /* What to do about these? */
6817 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6818 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6819 ERR("Cannot change the back buffer count yet\n");
6821 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6822 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6823 ERR("Cannot change the back buffer format yet\n");
6825 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6826 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6827 ERR("Cannot change the device window yet\n");
6829 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
6830 ERR("What do do about a changed auto depth stencil parameter?\n");
6833 if(pPresentationParameters
->Windowed
) {
6834 mode
.Width
= swapchain
->orig_width
;
6835 mode
.Height
= swapchain
->orig_height
;
6836 mode
.RefreshRate
= 0;
6837 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6839 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6840 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6841 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6842 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6845 /* Should Width == 800 && Height == 0 set 800x600? */
6846 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6847 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6848 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6855 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
6856 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
6860 if(!pPresentationParameters
->Windowed
) {
6861 DisplayModeChanged
= TRUE
;
6863 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6864 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6866 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6867 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6868 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6871 /* Now set the new viewport */
6872 IWineD3DDevice_SetViewport(iface
, &vp
);
6875 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6876 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6877 DisplayModeChanged
) {
6879 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6880 if(!pPresentationParameters
->Windowed
) {
6881 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
6884 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6886 /* Switching out of fullscreen mode? First set the original res, then change the window */
6887 if(pPresentationParameters
->Windowed
) {
6888 IWineD3DDevice_SetFullscreen(iface
, FALSE
);
6890 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6893 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6897 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6898 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6899 /** FIXME: always true at the moment **/
6900 if(!bEnableDialogs
) {
6901 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6907 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6908 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6909 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6911 *pParameters
= This
->createParms
;
6915 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6916 IWineD3DSwapChain
*swapchain
;
6917 HRESULT hrc
= WINED3D_OK
;
6919 TRACE("Relaying to swapchain\n");
6921 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6922 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
6923 IWineD3DSwapChain_Release(swapchain
);
6928 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6929 IWineD3DSwapChain
*swapchain
;
6930 HRESULT hrc
= WINED3D_OK
;
6932 TRACE("Relaying to swapchain\n");
6934 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6935 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6936 IWineD3DSwapChain_Release(swapchain
);
6942 /** ********************************************************
6943 * Notification functions
6944 ** ********************************************************/
6945 /** This function must be called in the release of a resource when ref == 0,
6946 * the contents of resource must still be correct,
6947 * any handels to other resource held by the caller must be closed
6948 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6949 *****************************************************/
6950 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6951 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6953 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
6954 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6957 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6958 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6960 TRACE("(%p) : Removing resource %p\n", This
, resource
);
6962 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6966 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6967 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6970 TRACE("(%p) : resource %p\n", This
, resource
);
6971 switch(IWineD3DResource_GetType(resource
)){
6972 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6973 case WINED3DRTYPE_SURFACE
: {
6976 /* Cleanup any FBO attachments if d3d is enabled */
6977 if(This
->d3d_initialized
) {
6978 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
6979 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
6981 TRACE("Last active render target destroyed\n");
6982 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6983 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6984 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6985 * and the lastActiveRenderTarget member shouldn't matter
6988 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
6989 TRACE("Activating primary back buffer\n");
6990 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
6991 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
6992 /* Single buffering environment */
6993 TRACE("Activating primary front buffer\n");
6994 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
6996 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6997 /* Implicit render target destroyed, that means the device is being destroyed
6998 * whatever we set here, it shouldn't matter
7000 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7003 /* May happen during ddraw uninitialization */
7004 TRACE("Render target set, but swapchain does not exist!\n");
7005 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7009 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7010 if (This
->fbo_color_attachments
[i
] == (IWineD3DSurface
*)resource
) {
7011 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
7012 set_render_target_fbo(iface
, i
, NULL
);
7013 This
->fbo_color_attachments
[i
] = NULL
;
7016 if (This
->fbo_depth_attachment
== (IWineD3DSurface
*)resource
) {
7017 bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->fbo
);
7018 set_depth_stencil_fbo(iface
, NULL
);
7019 This
->fbo_depth_attachment
= NULL
;
7025 case WINED3DRTYPE_TEXTURE
:
7026 case WINED3DRTYPE_CUBETEXTURE
:
7027 case WINED3DRTYPE_VOLUMETEXTURE
:
7028 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7029 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7030 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7031 This
->stateBlock
->textures
[counter
] = NULL
;
7033 if (This
->updateStateBlock
!= This
->stateBlock
){
7034 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7035 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7036 This
->updateStateBlock
->textures
[counter
] = NULL
;
7041 case WINED3DRTYPE_VOLUME
:
7042 /* TODO: nothing really? */
7044 case WINED3DRTYPE_VERTEXBUFFER
:
7045 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7048 TRACE("Cleaning up stream pointers\n");
7050 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7051 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7052 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7054 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7055 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7056 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7057 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7058 /* Set changed flag? */
7061 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) */
7062 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7063 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7064 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7067 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7068 else { /* This shouldn't happen */
7069 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7076 case WINED3DRTYPE_INDEXBUFFER
:
7077 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7078 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7079 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7080 This
->updateStateBlock
->pIndexData
= NULL
;
7083 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7084 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
7085 This
->stateBlock
->pIndexData
= NULL
;
7091 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7096 /* Remove the resoruce from the resourceStore */
7097 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7099 TRACE("Resource released\n");
7103 /**********************************************************
7104 * IWineD3DDevice VTbl follows
7105 **********************************************************/
7107 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7109 /*** IUnknown methods ***/
7110 IWineD3DDeviceImpl_QueryInterface
,
7111 IWineD3DDeviceImpl_AddRef
,
7112 IWineD3DDeviceImpl_Release
,
7113 /*** IWineD3DDevice methods ***/
7114 IWineD3DDeviceImpl_GetParent
,
7115 /*** Creation methods**/
7116 IWineD3DDeviceImpl_CreateVertexBuffer
,
7117 IWineD3DDeviceImpl_CreateIndexBuffer
,
7118 IWineD3DDeviceImpl_CreateStateBlock
,
7119 IWineD3DDeviceImpl_CreateSurface
,
7120 IWineD3DDeviceImpl_CreateTexture
,
7121 IWineD3DDeviceImpl_CreateVolumeTexture
,
7122 IWineD3DDeviceImpl_CreateVolume
,
7123 IWineD3DDeviceImpl_CreateCubeTexture
,
7124 IWineD3DDeviceImpl_CreateQuery
,
7125 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
7126 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7127 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7128 IWineD3DDeviceImpl_CreateVertexShader
,
7129 IWineD3DDeviceImpl_CreatePixelShader
,
7130 IWineD3DDeviceImpl_CreatePalette
,
7131 /*** Odd functions **/
7132 IWineD3DDeviceImpl_Init3D
,
7133 IWineD3DDeviceImpl_Uninit3D
,
7134 IWineD3DDeviceImpl_SetFullscreen
,
7135 IWineD3DDeviceImpl_SetMultithreaded
,
7136 IWineD3DDeviceImpl_EvictManagedResources
,
7137 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7138 IWineD3DDeviceImpl_GetBackBuffer
,
7139 IWineD3DDeviceImpl_GetCreationParameters
,
7140 IWineD3DDeviceImpl_GetDeviceCaps
,
7141 IWineD3DDeviceImpl_GetDirect3D
,
7142 IWineD3DDeviceImpl_GetDisplayMode
,
7143 IWineD3DDeviceImpl_SetDisplayMode
,
7144 IWineD3DDeviceImpl_GetHWND
,
7145 IWineD3DDeviceImpl_SetHWND
,
7146 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7147 IWineD3DDeviceImpl_GetRasterStatus
,
7148 IWineD3DDeviceImpl_GetSwapChain
,
7149 IWineD3DDeviceImpl_Reset
,
7150 IWineD3DDeviceImpl_SetDialogBoxMode
,
7151 IWineD3DDeviceImpl_SetCursorProperties
,
7152 IWineD3DDeviceImpl_SetCursorPosition
,
7153 IWineD3DDeviceImpl_ShowCursor
,
7154 IWineD3DDeviceImpl_TestCooperativeLevel
,
7155 /*** Getters and setters **/
7156 IWineD3DDeviceImpl_SetClipPlane
,
7157 IWineD3DDeviceImpl_GetClipPlane
,
7158 IWineD3DDeviceImpl_SetClipStatus
,
7159 IWineD3DDeviceImpl_GetClipStatus
,
7160 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7161 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7162 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7163 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7164 IWineD3DDeviceImpl_SetFVF
,
7165 IWineD3DDeviceImpl_GetFVF
,
7166 IWineD3DDeviceImpl_SetGammaRamp
,
7167 IWineD3DDeviceImpl_GetGammaRamp
,
7168 IWineD3DDeviceImpl_SetIndices
,
7169 IWineD3DDeviceImpl_GetIndices
,
7170 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7171 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7172 IWineD3DDeviceImpl_SetLight
,
7173 IWineD3DDeviceImpl_GetLight
,
7174 IWineD3DDeviceImpl_SetLightEnable
,
7175 IWineD3DDeviceImpl_GetLightEnable
,
7176 IWineD3DDeviceImpl_SetMaterial
,
7177 IWineD3DDeviceImpl_GetMaterial
,
7178 IWineD3DDeviceImpl_SetNPatchMode
,
7179 IWineD3DDeviceImpl_GetNPatchMode
,
7180 IWineD3DDeviceImpl_SetPaletteEntries
,
7181 IWineD3DDeviceImpl_GetPaletteEntries
,
7182 IWineD3DDeviceImpl_SetPixelShader
,
7183 IWineD3DDeviceImpl_GetPixelShader
,
7184 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7185 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7186 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7187 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7188 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7189 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7190 IWineD3DDeviceImpl_SetRenderState
,
7191 IWineD3DDeviceImpl_GetRenderState
,
7192 IWineD3DDeviceImpl_SetRenderTarget
,
7193 IWineD3DDeviceImpl_GetRenderTarget
,
7194 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7195 IWineD3DDeviceImpl_SetSamplerState
,
7196 IWineD3DDeviceImpl_GetSamplerState
,
7197 IWineD3DDeviceImpl_SetScissorRect
,
7198 IWineD3DDeviceImpl_GetScissorRect
,
7199 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7200 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7201 IWineD3DDeviceImpl_SetStreamSource
,
7202 IWineD3DDeviceImpl_GetStreamSource
,
7203 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7204 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7205 IWineD3DDeviceImpl_SetTexture
,
7206 IWineD3DDeviceImpl_GetTexture
,
7207 IWineD3DDeviceImpl_SetTextureStageState
,
7208 IWineD3DDeviceImpl_GetTextureStageState
,
7209 IWineD3DDeviceImpl_SetTransform
,
7210 IWineD3DDeviceImpl_GetTransform
,
7211 IWineD3DDeviceImpl_SetVertexDeclaration
,
7212 IWineD3DDeviceImpl_GetVertexDeclaration
,
7213 IWineD3DDeviceImpl_SetVertexShader
,
7214 IWineD3DDeviceImpl_GetVertexShader
,
7215 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7216 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7217 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7218 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7219 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7220 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7221 IWineD3DDeviceImpl_SetViewport
,
7222 IWineD3DDeviceImpl_GetViewport
,
7223 IWineD3DDeviceImpl_MultiplyTransform
,
7224 IWineD3DDeviceImpl_ValidateDevice
,
7225 IWineD3DDeviceImpl_ProcessVertices
,
7226 /*** State block ***/
7227 IWineD3DDeviceImpl_BeginStateBlock
,
7228 IWineD3DDeviceImpl_EndStateBlock
,
7229 /*** Scene management ***/
7230 IWineD3DDeviceImpl_BeginScene
,
7231 IWineD3DDeviceImpl_EndScene
,
7232 IWineD3DDeviceImpl_Present
,
7233 IWineD3DDeviceImpl_Clear
,
7235 IWineD3DDeviceImpl_DrawPrimitive
,
7236 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7237 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7238 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7239 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7240 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7241 IWineD3DDeviceImpl_DrawRectPatch
,
7242 IWineD3DDeviceImpl_DrawTriPatch
,
7243 IWineD3DDeviceImpl_DeletePatch
,
7244 IWineD3DDeviceImpl_ColorFill
,
7245 IWineD3DDeviceImpl_UpdateTexture
,
7246 IWineD3DDeviceImpl_UpdateSurface
,
7247 IWineD3DDeviceImpl_GetFrontBufferData
,
7248 /*** object tracking ***/
7249 IWineD3DDeviceImpl_ResourceReleased
7253 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
7254 WINED3DRS_ALPHABLENDENABLE
,
7255 WINED3DRS_ALPHAFUNC
,
7256 WINED3DRS_ALPHAREF
,
7257 WINED3DRS_ALPHATESTENABLE
,
7259 WINED3DRS_COLORWRITEENABLE
,
7260 WINED3DRS_DESTBLEND
,
7261 WINED3DRS_DITHERENABLE
,
7262 WINED3DRS_FILLMODE
,
7263 WINED3DRS_FOGDENSITY
,
7265 WINED3DRS_FOGSTART
,
7266 WINED3DRS_LASTPIXEL
,
7267 WINED3DRS_SHADEMODE
,
7268 WINED3DRS_SRCBLEND
,
7269 WINED3DRS_STENCILENABLE
,
7270 WINED3DRS_STENCILFAIL
,
7271 WINED3DRS_STENCILFUNC
,
7272 WINED3DRS_STENCILMASK
,
7273 WINED3DRS_STENCILPASS
,
7274 WINED3DRS_STENCILREF
,
7275 WINED3DRS_STENCILWRITEMASK
,
7276 WINED3DRS_STENCILZFAIL
,
7277 WINED3DRS_TEXTUREFACTOR
,
7288 WINED3DRS_ZWRITEENABLE
7291 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
7292 WINED3DTSS_ADDRESSW
,
7293 WINED3DTSS_ALPHAARG0
,
7294 WINED3DTSS_ALPHAARG1
,
7295 WINED3DTSS_ALPHAARG2
,
7296 WINED3DTSS_ALPHAOP
,
7297 WINED3DTSS_BUMPENVLOFFSET
,
7298 WINED3DTSS_BUMPENVLSCALE
,
7299 WINED3DTSS_BUMPENVMAT00
,
7300 WINED3DTSS_BUMPENVMAT01
,
7301 WINED3DTSS_BUMPENVMAT10
,
7302 WINED3DTSS_BUMPENVMAT11
,
7303 WINED3DTSS_COLORARG0
,
7304 WINED3DTSS_COLORARG1
,
7305 WINED3DTSS_COLORARG2
,
7306 WINED3DTSS_COLOROP
,
7307 WINED3DTSS_RESULTARG
,
7308 WINED3DTSS_TEXCOORDINDEX
,
7309 WINED3DTSS_TEXTURETRANSFORMFLAGS
7312 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
7313 WINED3DSAMP_ADDRESSU
,
7314 WINED3DSAMP_ADDRESSV
,
7315 WINED3DSAMP_ADDRESSW
,
7316 WINED3DSAMP_BORDERCOLOR
,
7317 WINED3DSAMP_MAGFILTER
,
7318 WINED3DSAMP_MINFILTER
,
7319 WINED3DSAMP_MIPFILTER
,
7320 WINED3DSAMP_MIPMAPLODBIAS
,
7321 WINED3DSAMP_MAXMIPLEVEL
,
7322 WINED3DSAMP_MAXANISOTROPY
,
7323 WINED3DSAMP_SRGBTEXTURE
,
7324 WINED3DSAMP_ELEMENTINDEX
7327 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
7329 WINED3DRS_AMBIENTMATERIALSOURCE
,
7330 WINED3DRS_CLIPPING
,
7331 WINED3DRS_CLIPPLANEENABLE
,
7332 WINED3DRS_COLORVERTEX
,
7333 WINED3DRS_DIFFUSEMATERIALSOURCE
,
7334 WINED3DRS_EMISSIVEMATERIALSOURCE
,
7335 WINED3DRS_FOGDENSITY
,
7337 WINED3DRS_FOGSTART
,
7338 WINED3DRS_FOGTABLEMODE
,
7339 WINED3DRS_FOGVERTEXMODE
,
7340 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
7341 WINED3DRS_LIGHTING
,
7342 WINED3DRS_LOCALVIEWER
,
7343 WINED3DRS_MULTISAMPLEANTIALIAS
,
7344 WINED3DRS_MULTISAMPLEMASK
,
7345 WINED3DRS_NORMALIZENORMALS
,
7346 WINED3DRS_PATCHEDGESTYLE
,
7347 WINED3DRS_POINTSCALE_A
,
7348 WINED3DRS_POINTSCALE_B
,
7349 WINED3DRS_POINTSCALE_C
,
7350 WINED3DRS_POINTSCALEENABLE
,
7351 WINED3DRS_POINTSIZE
,
7352 WINED3DRS_POINTSIZE_MAX
,
7353 WINED3DRS_POINTSIZE_MIN
,
7354 WINED3DRS_POINTSPRITEENABLE
,
7355 WINED3DRS_RANGEFOGENABLE
,
7356 WINED3DRS_SPECULARMATERIALSOURCE
,
7357 WINED3DRS_TWEENFACTOR
,
7358 WINED3DRS_VERTEXBLEND
,
7359 WINED3DRS_CULLMODE
,
7363 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
7364 WINED3DTSS_TEXCOORDINDEX
,
7365 WINED3DTSS_TEXTURETRANSFORMFLAGS
7368 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
7369 WINED3DSAMP_DMAPOFFSET
7372 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7373 DWORD rep
= StateTable
[state
].representative
;
7377 WineD3DContext
*context
;
7380 for(i
= 0; i
< This
->numContexts
; i
++) {
7381 context
= This
->contexts
[i
];
7382 if(isStateDirty(context
, rep
)) continue;
7384 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7387 context
->isStateDirty
[idx
] |= (1 << shift
);
7391 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7392 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7393 /* The drawable size of a pbuffer render target is the current pbuffer size
7395 *width
= dev
->pbufferWidth
;
7396 *height
= dev
->pbufferHeight
;
7399 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7400 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7402 *width
= This
->pow2Width
;
7403 *height
= This
->pow2Height
;
7406 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
7407 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
7408 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7409 * current context's drawable, which is the size of the back buffer of the swapchain
7410 * the active context belongs to. The back buffer of the swapchain is stored as the
7411 * surface the context belongs to.
7413 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
7414 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;