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 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader
);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->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 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY
, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE
, /* get current drawable for a DC */
60 X11DRV_GET_FONT
, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display
*get_display( HDC hdc
)
67 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
69 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
70 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface
= FALSE
;
77 /* static function declarations */
78 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
80 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
);
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * GLSL helper functions follow
153 **********************************************************/
155 /** Detach the GLSL pixel or vertex shader object from the shader program */
156 static void detach_glsl_shader(IWineD3DDevice
*iface
, GLhandleARB shaderObj
, GLhandleARB programId
) {
158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
160 if (shaderObj
!= 0 && programId
!= 0) {
161 TRACE_(d3d_shader
)("Detaching GLSL shader object %u from program %u\n", shaderObj
, programId
);
162 GL_EXTCALL(glDetachObjectARB(programId
, shaderObj
));
163 checkGLcall("glDetachObjectARB");
167 /** Delete a GLSL shader program */
168 static void delete_glsl_shader_program(IWineD3DDevice
*iface
, GLhandleARB obj
) {
170 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
173 TRACE_(d3d_shader
)("Deleting GLSL shader program %u\n", obj
);
174 GL_EXTCALL(glDeleteObjectARB(obj
));
175 checkGLcall("glDeleteObjectARB");
179 /** Delete the list of linked programs this shader is associated with.
180 * Also at this point, check to see if there are any objects left attached
181 * to each GLSL program. If not, delete the GLSL program object.
182 * This will be run when a device is released. */
183 static void delete_glsl_shader_list(IWineD3DDevice
* iface
) {
185 struct list
*ptr
= NULL
;
186 struct glsl_shader_prog_link
*curLink
= NULL
;
187 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
191 GLhandleARB objList
[2]; /* There should never be more than 2 objects attached
192 (one pixel shader and one vertex shader at most) */
194 ptr
= list_head( &This
->glsl_shader_progs
);
196 /* First, get the current item,
197 * save the link to the next pointer,
198 * detach and delete shader objects,
199 * then de-allocate the list item's memory */
200 curLink
= LIST_ENTRY( ptr
, struct glsl_shader_prog_link
, entry
);
201 ptr
= list_next( &This
->glsl_shader_progs
, ptr
);
203 /* See if this object is still attached to the program - it may have been detached already */
204 GL_EXTCALL(glGetAttachedObjectsARB(curLink
->programId
, 2, &numAttached
, objList
));
205 TRACE_(d3d_shader
)("%i GLSL objects are currently attached to program %u\n", numAttached
, curLink
->programId
);
206 for (i
= 0; i
< numAttached
; i
++) {
207 detach_glsl_shader(iface
, objList
[i
], curLink
->programId
);
210 delete_glsl_shader_program(iface
, curLink
->programId
);
212 /* Free the uniform locations */
213 HeapFree(GetProcessHeap(), 0, curLink
->vuniformF_locations
);
214 HeapFree(GetProcessHeap(), 0, curLink
->puniformF_locations
);
216 /* Free the memory for this list item */
217 HeapFree(GetProcessHeap(), 0, curLink
);
221 /**********************************************************
222 * IUnknown parts follows
223 **********************************************************/
225 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
227 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
229 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
230 if (IsEqualGUID(riid
, &IID_IUnknown
)
231 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
232 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
233 IUnknown_AddRef(iface
);
238 return E_NOINTERFACE
;
241 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
242 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
243 ULONG refCount
= InterlockedIncrement(&This
->ref
);
245 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
249 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
251 ULONG refCount
= InterlockedDecrement(&This
->ref
);
253 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
257 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
260 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
262 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
264 /* TODO: Clean up all the surfaces and textures! */
265 /* NOTE: You must release the parent if the object was created via a callback
266 ** ***************************/
268 /* Delete any GLSL shader programs that may exist */
269 if (This
->vs_selected_mode
== SHADER_GLSL
||
270 This
->ps_selected_mode
== SHADER_GLSL
)
271 delete_glsl_shader_list(iface
);
273 /* Release the update stateblock */
274 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
275 if(This
->updateStateBlock
!= This
->stateBlock
)
276 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
278 This
->updateStateBlock
= NULL
;
279 { /* because were not doing proper internal refcounts releasing the primary state block
280 causes recursion with the extra checks in ResourceReleased, to avoid this we have
281 to set this->stateBlock = NULL; first */
282 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
283 This
->stateBlock
= NULL
;
285 /* Release the stateblock */
286 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
287 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
291 if (This
->resources
!= NULL
) {
292 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
293 dumpResources(This
->resources
);
296 if(This
->contexts
) ERR("Context array not freed!\n");
298 IWineD3D_Release(This
->wineD3D
);
299 This
->wineD3D
= NULL
;
300 HeapFree(GetProcessHeap(), 0, This
);
301 TRACE("Freed device %p\n", This
);
307 /**********************************************************
308 * IWineD3DDevice implementation follows
309 **********************************************************/
310 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
311 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
312 *pParent
= This
->parent
;
313 IUnknown_AddRef(This
->parent
);
317 static void CreateVBO(IWineD3DVertexBufferImpl
*object
) {
318 IWineD3DDeviceImpl
*This
= object
->resource
.wineD3DDevice
; /* Needed for GL_EXTCALL */
319 GLenum error
, glUsage
;
320 DWORD vboUsage
= object
->resource
.usage
;
321 if(object
->Flags
& VBFLAG_VBOCREATEFAIL
) {
322 WARN("Creating a vbo failed once, not trying again\n");
326 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object
, debug_d3dusage(vboUsage
));
329 /* Make sure that the gl error is cleared. Do not use checkGLcall
330 * here because checkGLcall just prints a fixme and continues. However,
331 * if an error during VBO creation occurs we can fall back to non-vbo operation
332 * with full functionality(but performance loss)
334 while(glGetError() != GL_NO_ERROR
);
336 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
337 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
338 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
339 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
340 * to check if the rhw and color values are in the correct format.
343 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
344 error
= glGetError();
345 if(object
->vbo
== 0 || error
!= GL_NO_ERROR
) {
346 WARN("Failed to create a VBO with error %d\n", error
);
350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, object
->vbo
));
351 error
= glGetError();
352 if(error
!= GL_NO_ERROR
) {
353 WARN("Failed to bind the VBO, error %d\n", error
);
357 /* Don't use static, because dx apps tend to update the buffer
358 * quite often even if they specify 0 usage. Because we always keep the local copy
359 * we never read from the vbo and can create a write only opengl buffer.
361 switch(vboUsage
& (WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
) ) {
362 case WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
:
363 case WINED3DUSAGE_DYNAMIC
:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage
= GL_STREAM_DRAW_ARB
;
367 case WINED3DUSAGE_WRITEONLY
:
369 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
370 glUsage
= GL_DYNAMIC_DRAW_ARB
;
374 /* Reserve memory for the buffer. The amount of data won't change
375 * so we are safe with calling glBufferData once with a NULL ptr and
376 * calling glBufferSubData on updates
378 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
379 error
= glGetError();
380 if(error
!= GL_NO_ERROR
) {
381 WARN("glBufferDataARB failed with error %d\n", error
);
389 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
390 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
391 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
393 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
398 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
399 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
401 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
402 IWineD3DVertexBufferImpl
*object
;
403 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
404 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
408 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
409 *ppVertexBuffer
= NULL
;
410 return WINED3DERR_INVALIDCALL
;
413 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
415 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
416 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
418 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
419 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->resource
.size
);
423 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
424 * drawStridedFast (half-life 2).
426 * Basically converting the vertices in the buffer is quite expensive, and observations
427 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
428 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
430 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
431 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
432 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
433 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
435 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
436 * more. In this call we can convert dx7 buffers too.
438 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
439 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
) && Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) &&
440 (dxVersion
> 7 || !conv
) ) {
446 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
447 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
448 HANDLE
*sharedHandle
, IUnknown
*parent
) {
449 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
450 IWineD3DIndexBufferImpl
*object
;
451 TRACE("(%p) Creating index buffer\n", This
);
453 /* Allocate the storage for the device */
454 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
457 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
458 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,object
->resource
.size
);
461 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
462 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
463 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
468 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
471 IWineD3DStateBlockImpl
*object
;
475 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
476 object
->blockType
= Type
;
478 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
479 list_init(&object
->lightMap
[i
]);
482 /* Special case - Used during initialization to produce a placeholder stateblock
483 so other functions called can update a state block */
484 if (Type
== WINED3DSBT_INIT
) {
485 /* Don't bother increasing the reference count otherwise a device will never
486 be freed due to circular dependencies */
490 temp_result
= allocate_shader_constants(object
);
491 if (WINED3D_OK
!= temp_result
)
494 /* Otherwise, might as well set the whole state block to the appropriate values */
495 if (This
->stateBlock
!= NULL
)
496 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
498 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
500 /* Reset the ref and type after kludging it */
501 object
->wineD3DDevice
= This
;
503 object
->blockType
= Type
;
505 TRACE("Updating changed flags appropriate for type %d\n", Type
);
507 if (Type
== WINED3DSBT_ALL
) {
509 TRACE("ALL => Pretend everything has changed\n");
510 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
512 /* Lights are not part of the changed / set structure */
513 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
515 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
516 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
517 light
->changed
= TRUE
;
518 light
->enabledChanged
= TRUE
;
521 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
523 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
524 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
526 object
->changed
.pixelShader
= TRUE
;
528 /* Pixel Shader Constants */
529 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
)
530 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
531 for (i
= 0; i
< MAX_CONST_B
; ++i
)
532 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
533 for (i
= 0; i
< MAX_CONST_I
; ++i
)
534 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
536 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
537 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
539 for (j
= 0; j
< GL_LIMITS(texture_stages
); j
++) {
540 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
541 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
544 for (j
= 0 ; j
< 16; j
++) {
545 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
547 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
551 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
553 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
554 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
556 object
->changed
.vertexShader
= TRUE
;
558 /* Vertex Shader Constants */
559 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
)
560 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
561 for (i
= 0; i
< MAX_CONST_B
; ++i
)
562 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
563 for (i
= 0; i
< MAX_CONST_I
; ++i
)
564 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
566 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
567 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
569 for (j
= 0; j
< GL_LIMITS(texture_stages
); j
++) {
570 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
571 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
574 for (j
= 0 ; j
< 16; j
++){
575 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
576 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
580 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
582 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
583 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
584 light
->changed
= TRUE
;
585 light
->enabledChanged
= TRUE
;
589 FIXME("Unrecognized state block type %d\n", Type
);
592 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
597 /* ************************************
599 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
602 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
604 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.
606 ******************************** */
608 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
) {
609 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
610 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
611 unsigned int pow2Width
, pow2Height
;
612 unsigned int Size
= 1;
613 const PixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
);
614 TRACE("(%p) Create surface\n",This
);
616 /** FIXME: Check ranges on the inputs are valid
619 * [in] Quality level. The valid range is between zero and one less than the level
620 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
621 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
622 * values of paired render targets, depth stencil surfaces, and the MultiSample type
624 *******************************/
629 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 * If this flag is set, the contents of the depth stencil buffer will be
632 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
633 * with a different depth surface.
635 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
636 ***************************/
638 if(MultisampleQuality
< 0) {
639 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
640 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
643 if(MultisampleQuality
> 0) {
644 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
645 MultisampleQuality
=0;
648 /** FIXME: Check that the format is supported
650 *******************************/
652 /* Non-power2 support */
653 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
657 /* Find the nearest pow2 match */
658 pow2Width
= pow2Height
= 1;
659 while (pow2Width
< Width
) pow2Width
<<= 1;
660 while (pow2Height
< Height
) pow2Height
<<= 1;
663 if (pow2Width
> Width
|| pow2Height
> Height
) {
664 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
665 if (Format
== WINED3DFMT_DXT1
|| Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
666 || Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
667 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
668 This
, Width
, Height
);
669 return WINED3DERR_NOTAVAILABLE
;
673 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
674 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
676 *********************************/
677 if (WINED3DFMT_UNKNOWN
== Format
) {
679 } else if (Format
== WINED3DFMT_DXT1
) {
680 /* DXT1 is half byte per pixel */
681 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
683 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
684 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
685 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
687 /* The pitch is a multiple of 4 bytes */
688 Size
= ((Width
* tableEntry
->bpp
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
692 /** Create and initialise the surface resource **/
693 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
694 /* "Standalone" surface */
695 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
697 object
->currentDesc
.Width
= Width
;
698 object
->currentDesc
.Height
= Height
;
699 object
->currentDesc
.MultiSampleType
= MultiSample
;
700 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
702 /* Setup some glformat defaults */
703 object
->glDescription
.glFormat
= tableEntry
->glFormat
;
704 object
->glDescription
.glFormatInternal
= tableEntry
->glInternal
;
705 object
->glDescription
.glType
= tableEntry
->glType
;
707 object
->glDescription
.textureName
= 0;
708 object
->glDescription
.level
= Level
;
709 object
->glDescription
.target
= GL_TEXTURE_2D
;
712 object
->pow2Width
= pow2Width
;
713 object
->pow2Height
= pow2Height
;
716 object
->Flags
= 0; /* We start without flags set */
717 object
->Flags
|= (pow2Width
!= Width
|| pow2Height
!= Height
) ? SFLAG_NONPOW2
: 0;
718 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
719 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
720 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
723 if (WINED3DFMT_UNKNOWN
!= Format
) {
724 object
->bytesPerPixel
= tableEntry
->bpp
;
726 object
->bytesPerPixel
= 0;
729 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
731 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
733 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
734 * this function is too deep to need to care about things like this.
735 * Levels need to be checked too, and possibly Type since they all affect what can be done.
736 * ****************************************/
738 case WINED3DPOOL_SCRATCH
:
740 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
741 "which are mutually exclusive, setting lockable to TRUE\n");
744 case WINED3DPOOL_SYSTEMMEM
:
745 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
746 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
747 case WINED3DPOOL_MANAGED
:
748 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
749 "Usage of DYNAMIC which are mutually exclusive, not doing "
750 "anything just telling you.\n");
752 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
753 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
754 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
755 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
758 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
762 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
763 FIXME("Trying to create a render target that isn't in the default pool\n");
766 /* mark the texture as dirty so that it gets loaded first time around*/
767 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
768 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
769 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
770 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
772 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
773 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
774 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
776 /* Look at the implementation and set the correct Vtable */
779 /* Nothing to do, it's set already */
783 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
787 /* To be sure to catch this */
788 ERR("Unknown requested surface implementation %d!\n", Impl
);
789 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
790 return WINED3DERR_INVALIDCALL
;
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
798 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
799 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
800 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
803 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
804 IWineD3DTextureImpl
*object
;
809 unsigned int pow2Width
;
810 unsigned int pow2Height
;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN
>= Format
) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
821 return WINED3DERR_INVALIDCALL
;
824 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
825 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
826 object
->width
= Width
;
827 object
->height
= Height
;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
834 /* Find the nearest pow2 match */
835 pow2Width
= pow2Height
= 1;
836 while (pow2Width
< Width
) pow2Width
<<= 1;
837 while (pow2Height
< Height
) pow2Height
<<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object
->pow2scalingFactorX
= (((float)Width
) / ((float)pow2Width
));
843 object
->pow2scalingFactorY
= (((float)Height
) / ((float)pow2Height
));
844 TRACE(" xf(%f) yf(%f)\n", object
->pow2scalingFactorX
, object
->pow2scalingFactorY
);
846 /* Calculate levels for mip mapping */
848 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
849 object
->baseTexture
.levels
++;
852 while (tmpW
> 1 || tmpH
> 1) {
853 tmpW
= max(1, tmpW
>> 1);
854 tmpH
= max(1, tmpH
>> 1);
855 object
->baseTexture
.levels
++;
857 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
860 /* Generate all the surfaces */
863 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
865 /* use the callback to create the texture surface */
866 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, &object
->surfaces
[i
],NULL
);
867 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
868 FIXME("Failed to create surface %p\n", object
);
870 object
->surfaces
[i
] = NULL
;
871 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
877 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
878 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
879 /* calculate the next mipmap level */
880 tmpW
= max(1, tmpW
>> 1);
881 tmpH
= max(1, tmpH
>> 1);
884 TRACE("(%p) : Created texture %p\n", This
, object
);
888 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
889 UINT Width
, UINT Height
, UINT Depth
,
890 UINT Levels
, DWORD Usage
,
891 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
892 IWineD3DVolumeTexture
**ppVolumeTexture
,
893 HANDLE
*pSharedHandle
, IUnknown
*parent
,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
897 IWineD3DVolumeTextureImpl
*object
;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN
>= Format
) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
907 return WINED3DERR_INVALIDCALL
;
910 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
911 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
914 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
916 object
->width
= Width
;
917 object
->height
= Height
;
918 object
->depth
= Depth
;
920 /* Calculate levels for mip mapping */
922 object
->baseTexture
.levels
++;
926 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
927 tmpW
= max(1, tmpW
>> 1);
928 tmpH
= max(1, tmpH
>> 1);
929 tmpD
= max(1, tmpD
>> 1);
930 object
->baseTexture
.levels
++;
932 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
935 /* Generate all the surfaces */
940 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
943 /* Create the volume */
944 hr
= D3DCB_CreateVolume(This
->parent
, parent
, Width
, Height
, Depth
, Format
, Pool
, Usage
,
945 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
950 *ppVolumeTexture
= NULL
;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
957 /* calcualte the next mipmap level */
958 tmpW
= max(1, tmpW
>> 1);
959 tmpH
= max(1, tmpH
>> 1);
960 tmpD
= max(1, tmpD
>> 1);
963 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
964 TRACE("(%p) : Created volume texture %p\n", This
, object
);
968 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
969 UINT Width
, UINT Height
, UINT Depth
,
971 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
972 IWineD3DVolume
** ppVolume
,
973 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
975 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
976 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
977 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
);
979 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
982 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
984 object
->currentDesc
.Width
= Width
;
985 object
->currentDesc
.Height
= Height
;
986 object
->currentDesc
.Depth
= Depth
;
987 object
->bytesPerPixel
= formatDesc
->bpp
;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object
->lockable
= TRUE
;
991 object
->locked
= FALSE
;
992 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
993 object
->dirty
= TRUE
;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
998 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
999 UINT Levels
, DWORD Usage
,
1000 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1001 IWineD3DCubeTexture
**ppCubeTexture
,
1002 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1005 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1006 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1010 unsigned int pow2EdgeLength
= EdgeLength
;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN
>= Format
) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1016 return WINED3DERR_INVALIDCALL
;
1019 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1020 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1022 TRACE("(%p) Create Cube Texture\n", This
);
1024 /** Non-power2 support **/
1026 /* Find the nearest pow2 match */
1028 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1030 object
->edgeLength
= EdgeLength
;
1031 /* TODO: support for native non-power 2 */
1032 /* Precalculated scaling for 'faked' non power of two texture coords */
1033 object
->pow2scalingFactor
= ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1035 /* Calculate levels for mip mapping */
1037 object
->baseTexture
.levels
++;
1040 tmpW
= max(1, tmpW
>> 1);
1041 object
->baseTexture
.levels
++;
1043 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1046 /* Generate all the surfaces */
1048 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1050 /* Create the 6 faces */
1051 for (j
= 0; j
< 6; j
++) {
1053 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1054 i
/* Level */, &object
->surfaces
[j
][i
],pSharedHandle
);
1056 if(hr
!= WINED3D_OK
) {
1060 for (l
= 0; l
< j
; l
++) {
1061 IWineD3DSurface_Release(object
->surfaces
[j
][i
]);
1063 for (k
= 0; k
< i
; k
++) {
1064 for (l
= 0; l
< 6; l
++) {
1065 IWineD3DSurface_Release(object
->surfaces
[l
][j
]);
1069 FIXME("(%p) Failed to create surface\n",object
);
1070 HeapFree(GetProcessHeap(),0,object
);
1071 *ppCubeTexture
= NULL
;
1074 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1075 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1077 tmpW
= max(1, tmpW
>> 1);
1080 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1081 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1085 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1086 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1087 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1088 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1090 /* Just a check to see if we support this type of query */
1092 case WINED3DQUERYTYPE_OCCLUSION
:
1093 TRACE("(%p) occlusion query\n", This
);
1094 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1097 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1100 case WINED3DQUERYTYPE_EVENT
:
1101 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1102 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1104 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1108 case WINED3DQUERYTYPE_VCACHE
:
1109 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1110 case WINED3DQUERYTYPE_VERTEXSTATS
:
1111 case WINED3DQUERYTYPE_TIMESTAMP
:
1112 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1113 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1114 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1115 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1116 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1117 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1118 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1119 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1121 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1123 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1127 D3DCREATEOBJECTINSTANCE(object
, Query
)
1128 object
->type
= Type
;
1129 /* allocated the 'extended' data based on the type of query requested */
1131 case WINED3DQUERYTYPE_OCCLUSION
:
1132 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1133 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1134 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1135 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1138 case WINED3DQUERYTYPE_VCACHE
:
1139 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1140 case WINED3DQUERYTYPE_VERTEXSTATS
:
1141 case WINED3DQUERYTYPE_EVENT
:
1142 case WINED3DQUERYTYPE_TIMESTAMP
:
1143 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1144 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1145 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1146 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1147 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1148 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1149 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1150 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1152 object
->extendedData
= 0;
1153 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1155 TRACE("(%p) : Created Query %p\n", This
, object
);
1159 /*****************************************************************************
1160 * IWineD3DDeviceImpl_SetupFullscreenWindow
1162 * Helper function that modifies a HWND's Style and ExStyle for proper
1166 * iface: Pointer to the IWineD3DDevice interface
1167 * window: Window to setup
1169 *****************************************************************************/
1170 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1171 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1173 LONG style
, exStyle
;
1174 /* Don't do anything if an original style is stored.
1175 * That shouldn't happen
1177 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1178 if (This
->style
|| This
->exStyle
) {
1179 ERR("(%p): Want to change the window parameters of HWND %p, but "
1180 "another style is stored for restoration afterwards\n", This
, window
);
1183 /* Get the parameters and save them */
1184 style
= GetWindowLongW(window
, GWL_STYLE
);
1185 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1186 This
->style
= style
;
1187 This
->exStyle
= exStyle
;
1189 /* Filter out window decorations */
1190 style
&= ~WS_CAPTION
;
1191 style
&= ~WS_THICKFRAME
;
1192 exStyle
&= ~WS_EX_WINDOWEDGE
;
1193 exStyle
&= ~WS_EX_CLIENTEDGE
;
1195 /* Make sure the window is managed, otherwise we won't get keyboard input */
1196 style
|= WS_POPUP
| WS_SYSMENU
;
1198 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1199 This
->style
, This
->exStyle
, style
, exStyle
);
1201 SetWindowLongW(window
, GWL_STYLE
, style
);
1202 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1204 /* Inform the window about the update. */
1205 SetWindowPos(window
, HWND_TOP
, 0, 0,
1206 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1207 ShowWindow(window
, TRUE
);
1210 /*****************************************************************************
1211 * IWineD3DDeviceImpl_RestoreWindow
1213 * Helper function that restores a windows' properties when taking it out
1214 * of fullscreen mode
1217 * iface: Pointer to the IWineD3DDevice interface
1218 * window: Window to setup
1220 *****************************************************************************/
1221 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1222 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1224 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1225 * switch, do nothing
1227 if (!This
->style
&& !This
->exStyle
) return;
1229 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1230 This
, window
, This
->style
, This
->exStyle
);
1232 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1233 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1235 /* Delete the old values */
1239 /* Inform the window about the update */
1240 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1241 0, 0, 0, 0, /* Pos, Size, ignored */
1242 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1245 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1246 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1248 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1249 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1253 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1254 HRESULT hr
= WINED3D_OK
;
1255 IUnknown
*bufferParent
;
1258 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1260 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1261 * does a device hold a reference to a swap chain giving them a lifetime of the device
1262 * or does the swap chain notify the device of its destruction.
1263 *******************************/
1265 /* Check the params */
1266 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1267 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1268 return WINED3DERR_INVALIDCALL
;
1269 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1270 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");
1273 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1275 /*********************
1276 * Lookup the window Handle and the relating X window handle
1277 ********************/
1279 /* Setup hwnd we are using, plus which display this equates to */
1280 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1281 if (!object
->win_handle
) {
1282 object
->win_handle
= This
->createParms
.hFocusWindow
;
1285 object
->win_handle
= GetAncestor(object
->win_handle
, GA_ROOT
);
1286 if ( !( object
->win
= (Window
)GetPropA(object
->win_handle
, "__wine_x11_whole_window") ) ) {
1287 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object
->win_handle
);
1288 return WINED3DERR_NOTAVAILABLE
;
1290 hDc
= GetDC(object
->win_handle
);
1291 display
= get_display(hDc
);
1292 ReleaseDC(object
->win_handle
, hDc
);
1293 TRACE("Using a display of %p %p\n", display
, hDc
);
1295 if (NULL
== display
|| NULL
== hDc
) {
1296 WARN("Failed to get a display and HDc for Window %p\n", object
->win_handle
);
1297 return WINED3DERR_NOTAVAILABLE
;
1300 if (object
->win
== 0) {
1301 WARN("Failed to get a valid XVisuial ID for the window %p\n", object
->win_handle
);
1302 return WINED3DERR_NOTAVAILABLE
;
1305 object
->orig_width
= GetSystemMetrics(SM_CXSCREEN
);
1306 object
->orig_height
= GetSystemMetrics(SM_CYSCREEN
);
1307 object
->orig_fmt
= pixelformat_for_depth(GetDeviceCaps(hDc
, BITSPIXEL
) * GetDeviceCaps(hDc
, PLANES
));
1309 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1310 * then the corresponding dimension of the client area of the hDeviceWindow
1311 * (or the focus window, if hDeviceWindow is NULL) is taken.
1312 **********************/
1314 if (pPresentationParameters
->Windowed
&&
1315 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1316 (pPresentationParameters
->BackBufferHeight
== 0))) {
1319 GetClientRect(object
->win_handle
, &Rect
);
1321 if (pPresentationParameters
->BackBufferWidth
== 0) {
1322 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1323 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1325 if (pPresentationParameters
->BackBufferHeight
== 0) {
1326 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1327 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1331 /* Put the correct figures in the presentation parameters */
1332 TRACE("Copying across presentation parameters\n");
1333 object
->presentParms
= *pPresentationParameters
;
1335 TRACE("calling rendertarget CB\n");
1336 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1338 object
->presentParms
.BackBufferWidth
,
1339 object
->presentParms
.BackBufferHeight
,
1340 object
->presentParms
.BackBufferFormat
,
1341 object
->presentParms
.MultiSampleType
,
1342 object
->presentParms
.MultiSampleQuality
,
1343 TRUE
/* Lockable */,
1344 &object
->frontBuffer
,
1345 NULL
/* pShared (always null)*/);
1346 if (object
->frontBuffer
!= NULL
) {
1347 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1349 ERR("Failed to create the front buffer\n");
1354 * Create an opengl context for the display visual
1355 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1356 * use different properties after that point in time. FIXME: How to handle when requested format
1357 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1358 * it chooses is identical to the one already being used!
1359 **********************************/
1361 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1363 object
->context
= CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, display
, object
->win
);
1366 if (!object
->context
) {
1367 ERR("Failed to create a new context\n");
1368 hr
= WINED3DERR_NOTAVAILABLE
;
1371 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1372 object
->win_handle
, object
->context
->glCtx
, object
->win
);
1375 /*********************
1376 * Windowed / Fullscreen
1377 *******************/
1380 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1381 * so we should really check to see if there is a fullscreen swapchain already
1382 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1383 **************************************/
1385 if (!pPresentationParameters
->Windowed
) {
1392 /* Get info on the current display setup */
1394 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1397 /* Change the display settings */
1398 memset(&devmode
, 0, sizeof(DEVMODEW
));
1399 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1400 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1401 devmode
.dmPelsWidth
= pPresentationParameters
->BackBufferWidth
;
1402 devmode
.dmPelsHeight
= pPresentationParameters
->BackBufferHeight
;
1403 MultiByteToWideChar(CP_ACP
, 0, "Gamers CG", -1, devmode
.dmDeviceName
, CCHDEVICENAME
);
1404 ChangeDisplaySettingsExW(devmode
.dmDeviceName
, &devmode
, object
->win_handle
, CDS_FULLSCREEN
, NULL
);
1406 /* For GetDisplayMode */
1407 This
->ddraw_width
= devmode
.dmPelsWidth
;
1408 This
->ddraw_height
= devmode
.dmPelsHeight
;
1409 This
->ddraw_format
= pPresentationParameters
->BackBufferFormat
;
1411 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1413 /* And finally clip mouse to our screen */
1414 SetRect(&clip_rc
, 0, 0, devmode
.dmPelsWidth
, devmode
.dmPelsHeight
);
1415 ClipCursor(&clip_rc
);
1418 /*********************
1419 * Create the back, front and stencil buffers
1420 *******************/
1421 if(object
->presentParms
.BackBufferCount
> 0) {
1424 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1425 if(!object
->backBuffer
) {
1426 ERR("Out of memory\n");
1431 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1432 TRACE("calling rendertarget CB\n");
1433 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1435 object
->presentParms
.BackBufferWidth
,
1436 object
->presentParms
.BackBufferHeight
,
1437 object
->presentParms
.BackBufferFormat
,
1438 object
->presentParms
.MultiSampleType
,
1439 object
->presentParms
.MultiSampleQuality
,
1440 TRUE
/* Lockable */,
1441 &object
->backBuffer
[i
],
1442 NULL
/* pShared (always null)*/);
1443 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1444 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1446 ERR("Cannot create new back buffer\n");
1450 glDrawBuffer(GL_BACK
);
1451 checkGLcall("glDrawBuffer(GL_BACK)");
1455 object
->backBuffer
= NULL
;
1457 /* Single buffering - draw to front buffer */
1459 glDrawBuffer(GL_FRONT
);
1460 checkGLcall("glDrawBuffer(GL_FRONT)");
1464 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1465 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1466 TRACE("Creating depth stencil buffer\n");
1467 if (This
->depthStencilBuffer
== NULL
) {
1468 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1470 object
->presentParms
.BackBufferWidth
,
1471 object
->presentParms
.BackBufferHeight
,
1472 object
->presentParms
.AutoDepthStencilFormat
,
1473 object
->presentParms
.MultiSampleType
,
1474 object
->presentParms
.MultiSampleQuality
,
1475 FALSE
/* FIXME: Discard */,
1476 &This
->depthStencilBuffer
,
1477 NULL
/* pShared (always null)*/ );
1478 if (This
->depthStencilBuffer
!= NULL
)
1479 IWineD3DSurface_SetContainer(This
->depthStencilBuffer
, 0);
1482 /** TODO: A check on width, height and multisample types
1483 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1484 ****************************/
1485 object
->wantsDepthStencilBuffer
= TRUE
;
1487 object
->wantsDepthStencilBuffer
= FALSE
;
1490 TRACE("Created swapchain %p\n", object
);
1491 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1495 if (object
->backBuffer
) {
1497 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1498 if(object
->backBuffer
[i
]) {
1499 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1500 IUnknown_Release(bufferParent
); /* once for the get parent */
1501 if (IUnknown_Release(bufferParent
) > 0) {
1502 FIXME("(%p) Something's still holding the back buffer\n",This
);
1506 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1507 object
->backBuffer
= NULL
;
1509 if(object
->context
) {
1510 DestroyContext(This
, object
->context
);
1512 if(object
->frontBuffer
) {
1513 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1514 IUnknown_Release(bufferParent
); /* once for the get parent */
1515 if (IUnknown_Release(bufferParent
) > 0) {
1516 FIXME("(%p) Something's still holding the front buffer\n",This
);
1519 if(object
) HeapFree(GetProcessHeap(), 0, object
);
1523 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1524 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1525 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1526 TRACE("(%p)\n", This
);
1528 return This
->NumberOfSwapChains
;
1531 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1532 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1533 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1535 if(iSwapChain
< This
->NumberOfSwapChains
) {
1536 *pSwapChain
= This
->swapchains
[iSwapChain
];
1537 IWineD3DSwapChain_AddRef(*pSwapChain
);
1538 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1541 TRACE("Swapchain out of range\n");
1543 return WINED3DERR_INVALIDCALL
;
1548 * Vertex Declaration
1550 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1551 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, size_t element_count
) {
1552 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1553 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1554 HRESULT hr
= WINED3D_OK
;
1556 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1557 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1559 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1562 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1567 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1568 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1569 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1570 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1571 HRESULT hr
= WINED3D_OK
;
1572 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1573 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1575 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1577 if (vertex_declaration
) {
1578 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1581 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1583 if (WINED3D_OK
!= hr
) {
1584 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1585 IWineD3DVertexShader_Release(*ppVertexShader
);
1586 return WINED3DERR_INVALIDCALL
;
1592 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1593 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1594 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1595 HRESULT hr
= WINED3D_OK
;
1597 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1598 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1599 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1600 if (WINED3D_OK
== hr
) {
1601 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1603 WARN("(%p) : Failed to create pixel shader\n", This
);
1609 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1610 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1611 IWineD3DPaletteImpl
*object
;
1613 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1615 /* Create the new object */
1616 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1618 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1619 return E_OUTOFMEMORY
;
1622 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1624 object
->Flags
= Flags
;
1625 object
->parent
= Parent
;
1626 object
->wineD3DDevice
= This
;
1627 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1629 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1632 HeapFree( GetProcessHeap(), 0, object
);
1633 return E_OUTOFMEMORY
;
1636 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1638 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1642 *Palette
= (IWineD3DPalette
*) object
;
1647 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
1648 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1649 IWineD3DSwapChainImpl
*swapchain
;
1652 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
1653 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1655 /* TODO: Test if OpenGL is compiled in and loaded */
1657 /* Initialize the texture unit mapping to a 1:1 mapping */
1658 for(state
= 0; state
< MAX_SAMPLERS
; state
++) {
1659 This
->texUnitMap
[state
] = state
;
1661 This
->oneToOneTexUnitMap
= TRUE
;
1663 /* Setup the implicit swapchain */
1664 TRACE("Creating implicit swapchain\n");
1665 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
)) || !swapchain
) {
1666 WARN("Failed to create implicit swapchain\n");
1667 return WINED3DERR_INVALIDCALL
;
1670 This
->NumberOfSwapChains
= 1;
1671 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1672 if(!This
->swapchains
) {
1673 ERR("Out of memory!\n");
1674 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1675 return E_OUTOFMEMORY
;
1677 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1679 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, swapchain
->win_handle
);
1681 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1682 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1683 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1684 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
1687 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1688 This
->render_targets
[0] = swapchain
->frontBuffer
;
1689 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
1691 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1692 This
->activeContext
= swapchain
->context
;
1694 /* Depth Stencil support */
1695 This
->stencilBufferTarget
= This
->depthStencilBuffer
;
1696 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
1697 set_depth_stencil_fbo(iface
, This
->depthStencilBuffer
);
1699 if (NULL
!= This
->stencilBufferTarget
) {
1700 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1703 /* Set up some starting GL setup */
1706 * Initialize openGL extension related variables
1707 * with Default values
1710 ((IWineD3DImpl
*) This
->wineD3D
)->isGLInfoValid
= IWineD3DImpl_FillGLCaps( This
->wineD3D
, swapchain
->context
->display
);
1711 /* Setup all the devices defaults */
1712 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1714 IWineD3DImpl_CheckGraphicsMemory();
1717 /* Initialize our list of GLSL programs */
1718 list_init(&This
->glsl_shader_progs
);
1720 { /* Set a default viewport */
1724 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
1725 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
1728 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
1731 /* Initialize the current view state */
1732 This
->view_ident
= 1;
1733 This
->contexts
[0]->last_was_rhw
= 0;
1734 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1735 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1736 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1739 /* Clear the screen */
1740 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
, WINED3DCLEAR_STENCIL
|WINED3DCLEAR_ZBUFFER
|WINED3DCLEAR_TARGET
, 0x00, 1.0, 0);
1742 This
->d3d_initialized
= TRUE
;
1746 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
1747 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1750 TRACE("(%p)\n", This
);
1752 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1754 /* Delete the pbuffer context if there is any */
1755 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
1757 /* Delete the mouse cursor texture */
1758 if(This
->cursorTexture
) {
1760 glDeleteTextures(1, &This
->cursorTexture
);
1762 This
->cursorTexture
= 0;
1765 for(sampler
= 0; sampler
< GL_LIMITS(sampler_stages
); ++sampler
) {
1766 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
1769 /* Release the buffers (with sanity checks)*/
1770 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
1771 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
1772 if(This
->depthStencilBuffer
!= This
->stencilBufferTarget
)
1773 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This
);
1775 This
->stencilBufferTarget
= NULL
;
1777 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
1778 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
1779 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1781 TRACE("Setting rendertarget to NULL\n");
1782 This
->render_targets
[0] = NULL
;
1784 if (This
->depthStencilBuffer
) {
1785 if(D3DCB_DestroyDepthStencilSurface(This
->depthStencilBuffer
) > 0) {
1786 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This
);
1788 This
->depthStencilBuffer
= NULL
;
1791 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1792 TRACE("Releasing the implicit swapchain %d\n", i
);
1793 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1794 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1798 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1799 This
->swapchains
= NULL
;
1800 This
->NumberOfSwapChains
= 0;
1802 This
->d3d_initialized
= FALSE
;
1806 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
1807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1808 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
1810 /* Setup the window for fullscreen mode */
1811 if(fullscreen
&& !This
->ddraw_fullscreen
) {
1812 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
1813 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
1814 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
1817 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1818 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1819 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1822 This
->ddraw_fullscreen
= fullscreen
;
1825 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
1827 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1829 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
);
1832 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
1834 /* Resize the screen even without a window:
1835 * The app could have unset it with SetCooperativeLevel, but not called
1836 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1837 * but we don't have any hwnd
1840 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1841 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1842 if(devmode
.dmBitsPerPel
== 24) devmode
.dmBitsPerPel
= 32;
1843 devmode
.dmPelsWidth
= pMode
->Width
;
1844 devmode
.dmPelsHeight
= pMode
->Height
;
1846 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
1847 if (pMode
->RefreshRate
!= 0) {
1848 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1851 /* Only change the mode if necessary */
1852 if( (This
->ddraw_width
== pMode
->Width
) &&
1853 (This
->ddraw_height
== pMode
->Height
) &&
1854 (This
->ddraw_format
== pMode
->Format
) &&
1855 (pMode
->RefreshRate
== 0) ) {
1859 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1860 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
1861 if(devmode
.dmDisplayFrequency
!= 0) {
1862 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1863 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
1864 devmode
.dmDisplayFrequency
= 0;
1865 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
1867 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
1868 return DDERR_INVALIDMODE
;
1872 /* Store the new values */
1873 This
->ddraw_width
= pMode
->Width
;
1874 This
->ddraw_height
= pMode
->Height
;
1875 This
->ddraw_format
= pMode
->Format
;
1877 /* Only do this with a window of course */
1878 if(This
->ddraw_window
)
1879 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
1881 /* And finally clip mouse to our screen */
1882 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
1883 ClipCursor(&clip_rc
);
1888 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
1889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1890 *ppD3D
= This
->wineD3D
;
1891 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
1892 IWineD3D_AddRef(*ppD3D
);
1896 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
1897 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1898 * into the video ram as possible and seeing how many fit
1899 * you can also get the correct initial value from nvidia and ATI's driver via X
1900 * texture memory is video memory + AGP memory
1901 *******************/
1902 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1903 static BOOL showfixmes
= TRUE
;
1905 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This
,
1906 (wined3d_settings
.emulated_textureram
/(1024*1024)),
1907 ((wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
) / (1024*1024)));
1910 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
1911 (wined3d_settings
.emulated_textureram
/(1024*1024)),
1912 ((wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
) / (1024*1024)));
1913 /* return simulated texture memory left */
1914 return (wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
);
1922 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
1923 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1925 /* Update the current state block */
1926 This
->updateStateBlock
->changed
.fvf
= TRUE
;
1927 This
->updateStateBlock
->set
.fvf
= TRUE
;
1929 if(This
->updateStateBlock
->fvf
== fvf
) {
1930 TRACE("Application is setting the old fvf over, nothing to do\n");
1934 This
->updateStateBlock
->fvf
= fvf
;
1935 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
1936 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
1941 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
1942 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1943 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
1944 *pfvf
= This
->stateBlock
->fvf
;
1949 * Get / Set Stream Source
1951 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
1952 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1953 IWineD3DVertexBuffer
*oldSrc
;
1955 if (StreamNumber
>= MAX_STREAMS
) {
1956 WARN("Stream out of range %d\n", StreamNumber
);
1957 return WINED3DERR_INVALIDCALL
;
1960 oldSrc
= This
->stateBlock
->streamSource
[StreamNumber
];
1961 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This
, StreamNumber
, oldSrc
, pStreamData
, Stride
);
1963 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
1964 This
->updateStateBlock
->set
.streamSource
[StreamNumber
] = TRUE
;
1966 if(oldSrc
== pStreamData
&&
1967 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
1968 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
1969 TRACE("Application is setting the old values over, nothing to do\n");
1973 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
1975 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
1976 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
1979 /* Handle recording of state blocks */
1980 if (This
->isRecordingState
) {
1981 TRACE("Recording... not performing anything\n");
1985 /* Need to do a getParent and pass the reffs up */
1986 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
1987 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
1988 so for now, just count internally */
1989 if (pStreamData
!= NULL
) {
1990 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
1991 InterlockedIncrement(&vbImpl
->bindCount
);
1993 if (oldSrc
!= NULL
) {
1994 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
1997 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2002 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2003 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2005 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This
, StreamNumber
,
2006 This
->stateBlock
->streamSource
[StreamNumber
], This
->stateBlock
->streamStride
[StreamNumber
]);
2008 if (StreamNumber
>= MAX_STREAMS
) {
2009 WARN("Stream out of range %d\n", StreamNumber
);
2010 return WINED3DERR_INVALIDCALL
;
2012 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2013 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2015 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2018 if (*pStream
!= NULL
) {
2019 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2024 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2025 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2026 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2027 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2029 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2030 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2032 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2033 This
->updateStateBlock
->set
.streamFreq
[StreamNumber
] = TRUE
;
2034 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2036 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2037 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2038 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2044 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2045 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2047 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2048 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2050 TRACE("(%p) : returning %d\n", This
, *Divider
);
2056 * Get / Set & Multiply Transform
2058 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2059 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2061 /* Most of this routine, comments included copied from ddraw tree initially: */
2062 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2064 /* Handle recording of state blocks */
2065 if (This
->isRecordingState
) {
2066 TRACE("Recording... not performing anything\n");
2067 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2068 This
->updateStateBlock
->set
.transform
[d3dts
] = TRUE
;
2069 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2074 * If the new matrix is the same as the current one,
2075 * we cut off any further processing. this seems to be a reasonable
2076 * optimization because as was noticed, some apps (warcraft3 for example)
2077 * tend towards setting the same matrix repeatedly for some reason.
2079 * From here on we assume that the new matrix is different, wherever it matters.
2081 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2082 TRACE("The app is setting the same matrix over again\n");
2085 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2089 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2090 where ViewMat = Camera space, WorldMat = world space.
2092 In OpenGL, camera and world space is combined into GL_MODELVIEW
2093 matrix. The Projection matrix stay projection matrix.
2096 /* Capture the times we can just ignore the change for now */
2097 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2098 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2099 /* Handled by the state manager */
2102 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2106 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2107 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2108 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2109 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2113 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2114 WINED3DMATRIX
*mat
= NULL
;
2117 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2118 * below means it will be recorded in a state block change, but it
2119 * works regardless where it is recorded.
2120 * If this is found to be wrong, change to StateBlock.
2122 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2123 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2125 if (State
< HIGHEST_TRANSFORMSTATE
)
2127 mat
= &This
->updateStateBlock
->transforms
[State
];
2129 FIXME("Unhandled transform state!!\n");
2132 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2134 /* Apply change via set transform - will reapply to eg. lights this way */
2135 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2141 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2142 you can reference any indexes you want as long as that number max are enabled at any
2143 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2144 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2145 but when recording, just build a chain pretty much of commands to be replayed. */
2147 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2149 PLIGHTINFOEL
*object
= NULL
;
2150 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2154 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2156 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2157 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2158 if(object
->OriginalIndex
== Index
) break;
2163 TRACE("Adding new light\n");
2164 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2166 ERR("Out of memory error when allocating a light\n");
2167 return E_OUTOFMEMORY
;
2169 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2170 object
->glIndex
= -1;
2171 object
->OriginalIndex
= Index
;
2172 object
->changed
= TRUE
;
2175 /* Initialize the object */
2176 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
,
2177 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2178 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2179 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2180 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2181 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2182 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2184 /* Save away the information */
2185 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2187 switch (pLight
->Type
) {
2188 case WINED3DLIGHT_POINT
:
2190 object
->lightPosn
[0] = pLight
->Position
.x
;
2191 object
->lightPosn
[1] = pLight
->Position
.y
;
2192 object
->lightPosn
[2] = pLight
->Position
.z
;
2193 object
->lightPosn
[3] = 1.0f
;
2194 object
->cutoff
= 180.0f
;
2198 case WINED3DLIGHT_DIRECTIONAL
:
2200 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2201 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2202 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2203 object
->lightPosn
[3] = 0.0;
2204 object
->exponent
= 0.0f
;
2205 object
->cutoff
= 180.0f
;
2208 case WINED3DLIGHT_SPOT
:
2210 object
->lightPosn
[0] = pLight
->Position
.x
;
2211 object
->lightPosn
[1] = pLight
->Position
.y
;
2212 object
->lightPosn
[2] = pLight
->Position
.z
;
2213 object
->lightPosn
[3] = 1.0;
2216 object
->lightDirn
[0] = pLight
->Direction
.x
;
2217 object
->lightDirn
[1] = pLight
->Direction
.y
;
2218 object
->lightDirn
[2] = pLight
->Direction
.z
;
2219 object
->lightDirn
[3] = 1.0;
2222 * opengl-ish and d3d-ish spot lights use too different models for the
2223 * light "intensity" as a function of the angle towards the main light direction,
2224 * so we only can approximate very roughly.
2225 * however spot lights are rather rarely used in games (if ever used at all).
2226 * furthermore if still used, probably nobody pays attention to such details.
2228 if (pLight
->Falloff
== 0) {
2231 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2233 if (rho
< 0.0001) rho
= 0.0001f
;
2234 object
->exponent
= -0.3/log(cos(rho
/2));
2235 if (object
->exponent
> 128.0) {
2236 object
->exponent
= 128.0;
2238 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2244 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2247 /* Update the live definitions if the light is currently assigned a glIndex */
2248 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2249 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2254 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2255 PLIGHTINFOEL
*lightInfo
= NULL
;
2256 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2257 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2259 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2261 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2262 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2263 if(lightInfo
->OriginalIndex
== Index
) break;
2267 if (lightInfo
== NULL
) {
2268 TRACE("Light information requested but light not defined\n");
2269 return WINED3DERR_INVALIDCALL
;
2272 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2277 * Get / Set Light Enable
2278 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2280 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2281 PLIGHTINFOEL
*lightInfo
= NULL
;
2282 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2283 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2285 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2287 /* Tests show true = 128...not clear why */
2288 Enable
= Enable
? 128: 0;
2290 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2291 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2292 if(lightInfo
->OriginalIndex
== Index
) break;
2295 TRACE("Found light: %p\n", lightInfo
);
2297 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2298 if (lightInfo
== NULL
) {
2300 TRACE("Light enabled requested but light not defined, so defining one!\n");
2301 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2303 /* Search for it again! Should be fairly quick as near head of list */
2304 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2305 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2306 if(lightInfo
->OriginalIndex
== Index
) break;
2309 if (lightInfo
== NULL
) {
2310 FIXME("Adding default lights has failed dismally\n");
2311 return WINED3DERR_INVALIDCALL
;
2315 lightInfo
->enabledChanged
= TRUE
;
2317 if(lightInfo
->glIndex
!= -1) {
2318 if(!This
->isRecordingState
) {
2319 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2322 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2323 lightInfo
->glIndex
= -1;
2325 TRACE("Light already disabled, nothing to do\n");
2328 if (lightInfo
->glIndex
!= -1) {
2330 TRACE("Nothing to do as light was enabled\n");
2333 /* Find a free gl light */
2334 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2335 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2336 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2337 lightInfo
->glIndex
= i
;
2341 if(lightInfo
->glIndex
== -1) {
2342 ERR("Too many concurrently active lights\n");
2343 return WINED3DERR_INVALIDCALL
;
2346 /* i == lightInfo->glIndex */
2347 if(!This
->isRecordingState
) {
2348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2356 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2358 PLIGHTINFOEL
*lightInfo
= NULL
;
2359 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2361 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2362 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2364 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2365 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2366 if(lightInfo
->OriginalIndex
== Index
) break;
2370 if (lightInfo
== NULL
) {
2371 TRACE("Light enabled state requested but light not defined\n");
2372 return WINED3DERR_INVALIDCALL
;
2374 /* true is 128 according to SetLightEnable */
2375 *pEnable
= lightInfo
->glIndex
!= -1 ? 128 : 0;
2380 * Get / Set Clip Planes
2382 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2383 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2384 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2386 /* Validate Index */
2387 if (Index
>= GL_LIMITS(clipplanes
)) {
2388 TRACE("Application has requested clipplane this device doesn't support\n");
2389 return WINED3DERR_INVALIDCALL
;
2392 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2393 This
->updateStateBlock
->set
.clipplane
[Index
] = TRUE
;
2394 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2395 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2396 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2397 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2399 /* Handle recording of state blocks */
2400 if (This
->isRecordingState
) {
2401 TRACE("Recording... not performing anything\n");
2409 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2410 glMatrixMode(GL_MODELVIEW
);
2412 glLoadMatrixf((float *) &This
->stateBlock
->transforms
[WINED3DTS_VIEW
].u
.m
[0][0]);
2414 TRACE("Clipplane [%f,%f,%f,%f]\n",
2415 This
->updateStateBlock
->clipplane
[Index
][0],
2416 This
->updateStateBlock
->clipplane
[Index
][1],
2417 This
->updateStateBlock
->clipplane
[Index
][2],
2418 This
->updateStateBlock
->clipplane
[Index
][3]);
2419 glClipPlane(GL_CLIP_PLANE0
+ Index
, This
->updateStateBlock
->clipplane
[Index
]);
2420 checkGLcall("glClipPlane");
2428 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2429 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2430 TRACE("(%p) : for idx %d\n", This
, Index
);
2432 /* Validate Index */
2433 if (Index
>= GL_LIMITS(clipplanes
)) {
2434 TRACE("Application has requested clipplane this device doesn't support\n");
2435 return WINED3DERR_INVALIDCALL
;
2438 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2439 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2440 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2441 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2446 * Get / Set Clip Plane Status
2447 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2449 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2450 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2451 FIXME("(%p) : stub\n", This
);
2452 if (NULL
== pClipStatus
) {
2453 return WINED3DERR_INVALIDCALL
;
2455 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2456 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2460 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2461 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2462 FIXME("(%p) : stub\n", This
);
2463 if (NULL
== pClipStatus
) {
2464 return WINED3DERR_INVALIDCALL
;
2466 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2467 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2472 * Get / Set Material
2474 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2475 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2477 This
->updateStateBlock
->changed
.material
= TRUE
;
2478 This
->updateStateBlock
->set
.material
= TRUE
;
2479 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2481 /* Handle recording of state blocks */
2482 if (This
->isRecordingState
) {
2483 TRACE("Recording... not performing anything\n");
2488 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2489 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2490 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2491 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2492 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2493 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2494 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2495 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2496 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2498 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT
, (float*) &This
->updateStateBlock
->material
.Ambient
);
2499 checkGLcall("glMaterialfv(GL_AMBIENT)");
2500 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, (float*) &This
->updateStateBlock
->material
.Diffuse
);
2501 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2503 /* Only change material color if specular is enabled, otherwise it is set to black */
2504 if (This
->stateBlock
->renderState
[WINED3DRS_SPECULARENABLE
]) {
2505 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, (float*) &This
->updateStateBlock
->material
.Specular
);
2506 checkGLcall("glMaterialfv(GL_SPECULAR");
2508 float black
[4] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2509 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, &black
[0]);
2510 checkGLcall("glMaterialfv(GL_SPECULAR");
2512 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, (float*) &This
->updateStateBlock
->material
.Emissive
);
2513 checkGLcall("glMaterialfv(GL_EMISSION)");
2514 glMaterialf(GL_FRONT_AND_BACK
, GL_SHININESS
, This
->updateStateBlock
->material
.Power
);
2515 checkGLcall("glMaterialf(GL_SHININESS");
2521 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2523 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
2524 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2525 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2526 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2527 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2528 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2529 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2530 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2531 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2532 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2540 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
,
2541 UINT BaseVertexIndex
) {
2542 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2543 IWineD3DIndexBuffer
*oldIdxs
;
2544 UINT oldBaseIndex
= This
->updateStateBlock
->baseVertexIndex
;
2546 TRACE("(%p) : Setting to %p, base %d\n", This
, pIndexData
, BaseVertexIndex
);
2547 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2549 This
->updateStateBlock
->changed
.indices
= TRUE
;
2550 This
->updateStateBlock
->set
.indices
= TRUE
;
2551 This
->updateStateBlock
->pIndexData
= pIndexData
;
2552 This
->updateStateBlock
->baseVertexIndex
= BaseVertexIndex
;
2554 /* Handle recording of state blocks */
2555 if (This
->isRecordingState
) {
2556 TRACE("Recording... not performing anything\n");
2560 /* So far only the base vertex index is tracked */
2561 if(BaseVertexIndex
!= oldBaseIndex
) {
2562 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2567 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
, UINT
* pBaseVertexIndex
) {
2568 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2570 *ppIndexData
= This
->stateBlock
->pIndexData
;
2572 /* up ref count on ppindexdata */
2574 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
2575 *pBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
2576 TRACE("(%p) index data set to %p + %u\n", This
, ppIndexData
, This
->stateBlock
->baseVertexIndex
);
2578 TRACE("(%p) No index data set\n", This
);
2580 TRACE("Returning %p %d\n", *ppIndexData
, *pBaseVertexIndex
);
2585 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2586 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice
*iface
, UINT BaseIndex
) {
2587 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2588 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2590 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2591 TRACE("Application is setting the old value over, nothing to do\n");
2595 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2597 if (This
->isRecordingState
) {
2598 TRACE("Recording... not performing anything\n");
2601 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2606 * Get / Set Viewports
2608 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2609 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2611 TRACE("(%p)\n", This
);
2612 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2613 This
->updateStateBlock
->set
.viewport
= TRUE
;
2614 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
2616 /* Handle recording of state blocks */
2617 if (This
->isRecordingState
) {
2618 TRACE("Recording... not performing anything\n");
2622 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2623 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2625 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
2630 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
2631 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2632 TRACE("(%p)\n", This
);
2633 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
2638 * Get / Set Render States
2639 * TODO: Verify against dx9 definitions
2641 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
2643 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2644 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
2646 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
2648 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
2649 This
->updateStateBlock
->set
.renderState
[State
] = TRUE
;
2650 This
->updateStateBlock
->renderState
[State
] = Value
;
2652 /* Handle recording of state blocks */
2653 if (This
->isRecordingState
) {
2654 TRACE("Recording... not performing anything\n");
2658 /* Compared here and not before the assignment to allow proper stateblock recording */
2659 if(Value
== oldValue
) {
2660 TRACE("Application is setting the old value over, nothing to do\n");
2662 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
2668 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
2669 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2670 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
2671 *pValue
= This
->stateBlock
->renderState
[State
];
2676 * Get / Set Sampler States
2677 * TODO: Verify against dx9 definitions
2680 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
2681 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2682 DWORD oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2685 * SetSampler is designed to allow for more than the standard up to 8 textures
2686 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2687 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2689 * http://developer.nvidia.com/object/General_FAQ.html#t6
2691 * There are two new settings for GForce
2693 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2694 * and the texture one:
2695 * GL_MAX_TEXTURE_COORDS_ARB.
2696 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2698 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2699 if(Sampler
> GL_LIMITS(sampler_stages
) || Sampler
< 0 || Type
> WINED3D_HIGHEST_SAMPLER_STATE
|| Type
< 0) {
2700 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2701 Sampler
, debug_d3dsamplerstate(Type
), Type
, GL_LIMITS(sampler_stages
), WINED3D_HIGHEST_SAMPLER_STATE
);
2702 return WINED3DERR_INVALIDCALL
;
2705 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This
, Sampler
,
2706 debug_d3dsamplerstate(Type
), Type
, Value
);
2707 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
2708 This
->updateStateBlock
->set
.samplerState
[Sampler
][Type
] = Value
;
2709 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
2711 /* Handle recording of state blocks */
2712 if (This
->isRecordingState
) {
2713 TRACE("Recording... not performing anything\n");
2717 if(oldValue
== Value
) {
2718 TRACE("Application is setting the old value over, nothing to do\n");
2722 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
2727 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
2728 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2729 /** TODO: check that sampler is in range **/
2730 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2731 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This
, Sampler
, Type
, *Value
);
2736 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
2737 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2741 This
->updateStateBlock
->set
.scissorRect
= TRUE
;
2742 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
2743 memcpy(&This
->updateStateBlock
->scissorRect
, pRect
, sizeof(*pRect
));
2745 if(This
->isRecordingState
) {
2746 TRACE("Recording... not performing anything\n");
2750 GetClientRect(((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->win_handle
, &windowRect
);
2751 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2752 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2754 winHeight
= windowRect
.bottom
- windowRect
.top
;
2755 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->bottom
- winHeight
,
2756 pRect
->right
- pRect
->left
, pRect
->bottom
- pRect
->top
);
2758 glScissor(pRect
->left
, winHeight
- pRect
->bottom
, pRect
->right
- pRect
->left
, pRect
->bottom
- pRect
->top
);
2759 checkGLcall("glScissor");
2765 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
2766 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2768 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
2769 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
2773 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
2774 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2775 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
2777 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
2779 This
->updateStateBlock
->vertexDecl
= pDecl
;
2780 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
2781 This
->updateStateBlock
->set
.vertexDecl
= TRUE
;
2783 if (This
->isRecordingState
) {
2784 TRACE("Recording... not performing anything\n");
2786 } else if(pDecl
== oldDecl
) {
2787 /* Checked after the assignment to allow proper stateblock recording */
2788 TRACE("Application is setting the old declaration over, nothing to do\n");
2792 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2796 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
2797 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2799 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
2801 *ppDecl
= This
->stateBlock
->vertexDecl
;
2802 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
2806 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
2807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2808 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
2810 This
->updateStateBlock
->vertexShader
= pShader
;
2811 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
2812 This
->updateStateBlock
->set
.vertexShader
= TRUE
;
2814 if (This
->isRecordingState
) {
2815 TRACE("Recording... not performing anything\n");
2817 } else if(oldShader
== pShader
) {
2818 /* Checked here to allow proper stateblock recording */
2819 TRACE("App is setting the old shader over, nothing to do\n");
2823 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
2825 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
2830 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
2831 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2833 if (NULL
== ppShader
) {
2834 return WINED3DERR_INVALIDCALL
;
2836 *ppShader
= This
->stateBlock
->vertexShader
;
2837 if( NULL
!= *ppShader
)
2838 IWineD3DVertexShader_AddRef(*ppShader
);
2840 TRACE("(%p) : returning %p\n", This
, *ppShader
);
2844 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
2845 IWineD3DDevice
*iface
,
2847 CONST BOOL
*srcData
,
2850 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2851 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
2853 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2854 iface
, srcData
, start
, count
);
2856 if (srcData
== NULL
|| cnt
< 0)
2857 return WINED3DERR_INVALIDCALL
;
2859 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
2860 for (i
= 0; i
< cnt
; i
++)
2861 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
2863 for (i
= start
; i
< cnt
+ start
; ++i
) {
2864 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
2865 This
->updateStateBlock
->set
.vertexShaderConstantsB
[i
] = TRUE
;
2868 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2873 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
2874 IWineD3DDevice
*iface
,
2879 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2880 int cnt
= min(count
, MAX_CONST_B
- start
);
2882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2883 iface
, dstData
, start
, count
);
2885 if (dstData
== NULL
|| cnt
< 0)
2886 return WINED3DERR_INVALIDCALL
;
2888 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
2892 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
2893 IWineD3DDevice
*iface
,
2898 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2899 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
2901 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2902 iface
, srcData
, start
, count
);
2904 if (srcData
== NULL
|| cnt
< 0)
2905 return WINED3DERR_INVALIDCALL
;
2907 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
2908 for (i
= 0; i
< cnt
; i
++)
2909 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
2910 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2912 for (i
= start
; i
< cnt
+ start
; ++i
) {
2913 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
2914 This
->updateStateBlock
->set
.vertexShaderConstantsI
[i
] = TRUE
;
2917 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2922 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
2923 IWineD3DDevice
*iface
,
2928 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2929 int cnt
= min(count
, MAX_CONST_I
- start
);
2931 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2932 iface
, dstData
, start
, count
);
2934 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
2935 return WINED3DERR_INVALIDCALL
;
2937 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
2941 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
2942 IWineD3DDevice
*iface
,
2944 CONST
float *srcData
,
2947 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2948 int i
, cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
2950 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2951 iface
, srcData
, start
, count
);
2953 if (srcData
== NULL
|| ((signed int) GL_LIMITS(vshader_constantsF
) - (signed int) start
) <= (signed int) 0)
2954 return WINED3DERR_INVALIDCALL
;
2956 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, cnt
* sizeof(float) * 4);
2957 for (i
= 0; i
< cnt
; i
++)
2958 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
2959 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2961 for (i
= start
; i
< cnt
+ start
; ++i
) {
2962 if (!This
->updateStateBlock
->set
.vertexShaderConstantsF
[i
]) {
2963 constant_entry
*ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry
));
2965 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
2966 This
->updateStateBlock
->set
.vertexShaderConstantsF
[i
] = TRUE
;
2968 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
2971 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2976 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
2977 IWineD3DDevice
*iface
,
2982 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2983 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
2985 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2986 iface
, dstData
, start
, count
);
2988 if (dstData
== NULL
|| cnt
< 0)
2989 return WINED3DERR_INVALIDCALL
;
2991 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
2995 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
2997 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
2998 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3002 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3004 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3005 * it is never called.
3008 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3009 * that would be really messy and require shader recompilation
3010 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3011 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3012 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3013 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3015 if(This
->stateBlock
->pixelShader
|| This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3016 if(This
->oneToOneTexUnitMap
) {
3017 TRACE("Not touching 1:1 map\n");
3020 TRACE("Restoring 1:1 texture unit mapping\n");
3021 /* Restore a 1:1 mapping */
3022 for(i
= 0; i
< MAX_SAMPLERS
; i
++) {
3023 if(This
->texUnitMap
[i
] != i
) {
3024 This
->texUnitMap
[i
] = i
;
3025 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3026 markTextureStagesDirty(This
, i
);
3029 This
->oneToOneTexUnitMap
= TRUE
;
3032 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3033 * First, see if we can succeed at all
3036 for(i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3037 if(This
->stateBlock
->textures
[i
] == NULL
) tex
++;
3040 if(GL_LIMITS(textures
) + tex
< This
->stateBlock
->lowest_disabled_stage
) {
3041 FIXME("Too many bound textures to support the combiner settings\n");
3045 /* Now work out the mapping */
3047 This
->oneToOneTexUnitMap
= FALSE
;
3048 WARN("Non 1:1 mapping UNTESTED!\n");
3049 for(i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3050 /* Skip NULL textures */
3051 if (!This
->stateBlock
->textures
[i
]) {
3052 /* Map to -1, so the check below doesn't fail if a non-NULL
3053 * texture is set on this stage */
3054 TRACE("Mapping texture stage %d to -1\n", i
);
3055 This
->texUnitMap
[i
] = -1;
3060 TRACE("Mapping texture stage %d to unit %d\n", i
, tex
);
3061 if(This
->texUnitMap
[i
] != tex
) {
3062 This
->texUnitMap
[i
] = tex
;
3063 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3064 markTextureStagesDirty(This
, i
);
3072 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3073 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3074 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3075 This
->updateStateBlock
->pixelShader
= pShader
;
3076 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3077 This
->updateStateBlock
->set
.pixelShader
= TRUE
;
3079 /* Handle recording of state blocks */
3080 if (This
->isRecordingState
) {
3081 TRACE("Recording... not performing anything\n");
3084 if (This
->isRecordingState
) {
3085 TRACE("Recording... not performing anything\n");
3089 if(pShader
== oldShader
) {
3090 TRACE("App is setting the old pixel shader over, nothing to do\n");
3094 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3095 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3097 /* Rebuild the texture unit mapping if nvrc's are supported */
3098 if(GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
3099 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3105 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3106 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3108 if (NULL
== ppShader
) {
3109 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3110 return WINED3DERR_INVALIDCALL
;
3113 *ppShader
= This
->stateBlock
->pixelShader
;
3114 if (NULL
!= *ppShader
) {
3115 IWineD3DPixelShader_AddRef(*ppShader
);
3117 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3121 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3122 IWineD3DDevice
*iface
,
3124 CONST BOOL
*srcData
,
3127 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3128 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3130 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3131 iface
, srcData
, start
, count
);
3133 if (srcData
== NULL
|| cnt
< 0)
3134 return WINED3DERR_INVALIDCALL
;
3136 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3137 for (i
= 0; i
< cnt
; i
++)
3138 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3140 for (i
= start
; i
< cnt
+ start
; ++i
) {
3141 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3142 This
->updateStateBlock
->set
.pixelShaderConstantsB
[i
] = TRUE
;
3145 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3150 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3151 IWineD3DDevice
*iface
,
3156 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3157 int cnt
= min(count
, MAX_CONST_B
- start
);
3159 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3160 iface
, dstData
, start
, count
);
3162 if (dstData
== NULL
|| cnt
< 0)
3163 return WINED3DERR_INVALIDCALL
;
3165 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3169 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3170 IWineD3DDevice
*iface
,
3175 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3176 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3178 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3179 iface
, srcData
, start
, count
);
3181 if (srcData
== NULL
|| cnt
< 0)
3182 return WINED3DERR_INVALIDCALL
;
3184 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3185 for (i
= 0; i
< cnt
; i
++)
3186 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3187 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3189 for (i
= start
; i
< cnt
+ start
; ++i
) {
3190 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3191 This
->updateStateBlock
->set
.pixelShaderConstantsI
[i
] = TRUE
;
3194 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3199 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3200 IWineD3DDevice
*iface
,
3205 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3206 int cnt
= min(count
, MAX_CONST_I
- start
);
3208 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3209 iface
, dstData
, start
, count
);
3211 if (dstData
== NULL
|| cnt
< 0)
3212 return WINED3DERR_INVALIDCALL
;
3214 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3218 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3219 IWineD3DDevice
*iface
,
3221 CONST
float *srcData
,
3224 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3225 int i
, cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3227 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3228 iface
, srcData
, start
, count
);
3230 if (srcData
== NULL
|| cnt
< 0)
3231 return WINED3DERR_INVALIDCALL
;
3233 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, cnt
* sizeof(float) * 4);
3234 for (i
= 0; i
< cnt
; i
++)
3235 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3236 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3238 for (i
= start
; i
< cnt
+ start
; ++i
) {
3239 if (!This
->updateStateBlock
->set
.pixelShaderConstantsF
[i
]) {
3240 constant_entry
*ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry
));
3242 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3243 This
->updateStateBlock
->set
.pixelShaderConstantsF
[i
] = TRUE
;
3245 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3248 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3253 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3254 IWineD3DDevice
*iface
,
3259 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3260 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3262 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3263 iface
, dstData
, start
, count
);
3265 if (dstData
== NULL
|| cnt
< 0)
3266 return WINED3DERR_INVALIDCALL
;
3268 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3272 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3274 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, DWORD SrcFVF
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3275 char *dest_ptr
, *dest_conv
= NULL
;
3277 DWORD DestFVF
= dest
->fvf
;
3279 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3283 if (SrcFVF
& WINED3DFVF_NORMAL
) {
3284 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3287 if ( (SrcFVF
& WINED3DFVF_POSITION_MASK
) != WINED3DFVF_XYZ
) {
3288 ERR("Source has no position mask\n");
3289 return WINED3DERR_INVALIDCALL
;
3292 /* We might access VBOs from this code, so hold the lock */
3295 if (dest
->resource
.allocatedMemory
== NULL
) {
3296 /* This may happen if we do direct locking into a vbo. Unlikely,
3297 * but theoretically possible(ddraw processvertices test)
3299 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3300 if(!dest
->resource
.allocatedMemory
) {
3302 ERR("Out of memory\n");
3303 return E_OUTOFMEMORY
;
3307 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3308 checkGLcall("glBindBufferARB");
3309 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3311 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3313 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3314 checkGLcall("glUnmapBufferARB");
3318 /* Get a pointer into the destination vbo(create one if none exists) and
3319 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3321 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3326 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3327 dest_conv
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
));
3329 ERR("glMapBuffer failed\n");
3330 /* Continue without storing converted vertices */
3335 * a) WINED3DRS_CLIPPING is enabled
3336 * b) WINED3DVOP_CLIP is passed
3338 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3339 static BOOL warned
= FALSE
;
3341 * The clipping code is not quite correct. Some things need
3342 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3343 * so disable clipping for now.
3344 * (The graphics in Half-Life are broken, and my processvertices
3345 * test crashes with IDirect3DDevice3)
3351 FIXME("Clipping is broken and disabled for now\n");
3353 } else doClip
= FALSE
;
3354 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3356 dest_conv
= ((char *) dest_conv
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3359 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3362 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3363 WINED3DTS_PROJECTION
,
3365 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3366 WINED3DTS_WORLDMATRIX(0),
3369 TRACE("View mat:\n");
3370 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
);
3371 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
);
3372 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
);
3373 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
);
3375 TRACE("Proj mat:\n");
3376 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
);
3377 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
);
3378 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
);
3379 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
);
3381 TRACE("World mat:\n");
3382 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
);
3383 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
);
3384 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
);
3385 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
);
3387 /* Get the viewport */
3388 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3389 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3390 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3392 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3393 multiply_matrix(&mat
,&proj_mat
,&mat
);
3395 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3397 for (i
= 0; i
< dwCount
; i
+= 1) {
3398 unsigned int tex_index
;
3400 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3401 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3402 /* The position first */
3404 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
3406 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3408 /* Multiplication with world, view and projection matrix */
3409 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
);
3410 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
);
3411 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
);
3412 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
);
3414 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3416 /* WARNING: The following things are taken from d3d7 and were not yet checked
3417 * against d3d8 or d3d9!
3420 /* Clipping conditions: From
3421 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3423 * A vertex is clipped if it does not match the following requirements
3427 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3429 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3430 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3435 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3436 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3439 /* "Normal" viewport transformation (not clipped)
3440 * 1) The values are divided by rhw
3441 * 2) The y axis is negative, so multiply it with -1
3442 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3443 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3444 * 4) Multiply x with Width/2 and add Width/2
3445 * 5) The same for the height
3446 * 6) Add the viewpoint X and Y to the 2D coordinates and
3447 * The minimum Z value to z
3448 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3450 * Well, basically it's simply a linear transformation into viewport
3462 z
*= vp
.MaxZ
- vp
.MinZ
;
3464 x
+= vp
.Width
/ 2 + vp
.X
;
3465 y
+= vp
.Height
/ 2 + vp
.Y
;
3470 /* That vertex got clipped
3471 * Contrary to OpenGL it is not dropped completely, it just
3472 * undergoes a different calculation.
3474 TRACE("Vertex got clipped\n");
3481 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3482 * outside of the main vertex buffer memory. That needs some more
3487 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3490 ( (float *) dest_ptr
)[0] = x
;
3491 ( (float *) dest_ptr
)[1] = y
;
3492 ( (float *) dest_ptr
)[2] = z
;
3493 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3495 dest_ptr
+= 3 * sizeof(float);
3497 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3498 dest_ptr
+= sizeof(float);
3503 ( (float *) dest_conv
)[0] = x
* w
;
3504 ( (float *) dest_conv
)[1] = y
* w
;
3505 ( (float *) dest_conv
)[2] = z
* w
;
3506 ( (float *) dest_conv
)[3] = w
;
3508 dest_conv
+= 3 * sizeof(float);
3510 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3511 dest_conv
+= sizeof(float);
3515 if (DestFVF
& WINED3DFVF_PSIZE
) {
3516 dest_ptr
+= sizeof(DWORD
);
3517 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
3519 if (DestFVF
& WINED3DFVF_NORMAL
) {
3521 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
3522 /* AFAIK this should go into the lighting information */
3523 FIXME("Didn't expect the destination to have a normal\n");
3524 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
3526 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
3530 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
3532 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
3534 static BOOL warned
= FALSE
;
3537 ERR("No diffuse color in source, but destination has one\n");
3541 *( (DWORD
*) dest_ptr
) = 0xffffffff;
3542 dest_ptr
+= sizeof(DWORD
);
3545 *( (DWORD
*) dest_conv
) = 0xffffffff;
3546 dest_conv
+= sizeof(DWORD
);
3550 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
3552 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
3553 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
3554 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
3555 dest_conv
+= sizeof(DWORD
);
3560 if (DestFVF
& WINED3DFVF_SPECULAR
) {
3561 /* What's the color value in the feedback buffer? */
3563 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
3565 static BOOL warned
= FALSE
;
3568 ERR("No specular color in source, but destination has one\n");
3572 *( (DWORD
*) dest_ptr
) = 0xFF000000;
3573 dest_ptr
+= sizeof(DWORD
);
3576 *( (DWORD
*) dest_conv
) = 0xFF000000;
3577 dest_conv
+= sizeof(DWORD
);
3581 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
3583 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
3584 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
3585 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
3586 dest_conv
+= sizeof(DWORD
);
3591 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
3593 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
3594 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
3596 ERR("No source texture, but destination requests one\n");
3597 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3598 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3601 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3603 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3610 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3611 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3618 #undef copy_and_next
3620 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexBuffer
* pVertexDecl
, DWORD Flags
) {
3621 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3622 IWineD3DVertexBufferImpl
*SrcImpl
= (IWineD3DVertexBufferImpl
*) pVertexDecl
;
3623 WineDirect3DVertexStridedData strided
;
3624 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
3627 WARN("NULL source vertex buffer\n");
3628 return WINED3DERR_INVALIDCALL
;
3630 /* We don't need the source vbo because this buffer is only used as
3631 * a source for ProcessVertices. Avoid wasting resources by converting the
3632 * buffer and loading the VBO
3635 TRACE("Releasing the source vbo, it won't be needed\n");
3637 if(!SrcImpl
->resource
.allocatedMemory
) {
3638 /* Rescue the data from the buffer */
3640 SrcImpl
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, SrcImpl
->resource
.size
);
3641 if(!SrcImpl
->resource
.allocatedMemory
) {
3642 ERR("Out of memory\n");
3643 return E_OUTOFMEMORY
;
3647 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, SrcImpl
->vbo
));
3648 checkGLcall("glBindBufferARB");
3650 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3652 memcpy(SrcImpl
->resource
.allocatedMemory
, src
, SrcImpl
->resource
.size
);
3655 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3656 checkGLcall("glUnmapBufferARB");
3661 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, 0));
3662 checkGLcall("glBindBufferARB");
3663 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl
->vbo
));
3664 checkGLcall("glDeleteBuffersARB");
3670 memset(&strided
, 0, sizeof(strided
));
3671 primitiveConvertFVFtoOffset(SrcImpl
->fvf
, get_flexible_vertex_size(SrcImpl
->fvf
), SrcImpl
->resource
.allocatedMemory
+ get_flexible_vertex_size(SrcImpl
->fvf
) * SrcStartIndex
, &strided
, 0, 0);
3673 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, SrcImpl
->fvf
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
3677 * Get / Set Texture Stage States
3678 * TODO: Verify against dx9 definitions
3680 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
3681 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3682 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3684 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3686 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
3688 /* Reject invalid texture units */
3689 if (Stage
>= GL_LIMITS(texture_stages
)) {
3690 TRACE("Attempt to access invalid texture rejected\n");
3691 return WINED3DERR_INVALIDCALL
;
3694 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
3695 This
->updateStateBlock
->set
.textureState
[Stage
][Type
] = TRUE
;
3696 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
3698 if (This
->isRecordingState
) {
3699 TRACE("Recording... not performing anything\n");
3703 /* Checked after the assignments to allow proper stateblock recording */
3704 if(oldValue
== Value
) {
3705 TRACE("App is setting the old value over, nothing to do\n");
3709 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
3710 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
3711 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3712 * Changes in other states are important on disabled stages too
3717 if(Type
== WINED3DTSS_COLOROP
) {
3720 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
3721 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3722 * they have to be disabled
3724 * The current stage is dirtified below.
3726 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3727 TRACE("Additionally dirtifying stage %d\n", i
);
3728 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3730 This
->stateBlock
->lowest_disabled_stage
= Stage
;
3731 TRACE("New lowest disabled: %d\n", Stage
);
3732 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
3733 /* Previously disabled stage enabled. Stages above it may need enabling
3734 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3735 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3737 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3740 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
3741 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
3744 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
3745 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3747 This
->stateBlock
->lowest_disabled_stage
= i
;
3748 TRACE("New lowest disabled: %d\n", i
);
3750 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
3751 /* TODO: Built a stage -> texture unit mapping for register combiners */
3755 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
3757 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3758 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3759 * will call FindTexUnitMap too.
3761 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
3762 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3767 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
3768 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3769 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
3770 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3777 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
3779 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3780 IWineD3DBaseTexture
*oldTexture
;
3782 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
3783 TRACE("(%p) : Stage(%d), Texture (%p)\n", This
, Stage
, pTexture
);
3785 #if 0 /* TODO: check so vertex textures */
3786 if (Stage
>= D3DVERTEXTEXTURESAMPLER
&& Stage
<= D3DVERTEXTEXTURESAMPLER3
){
3787 This
->updateStateBlock
->vertexTextures
[Stage
- D3DVERTEXTEXTURESAMPLER
] = pTexture
;
3792 /* Reject invalid texture units */
3793 if (Stage
>= GL_LIMITS(sampler_stages
) || Stage
< 0) {
3794 WARN("Attempt to access invalid texture rejected\n");
3795 return WINED3DERR_INVALIDCALL
;
3798 if(pTexture
!= NULL
) {
3799 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3801 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
3802 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
3803 return WINED3DERR_INVALIDCALL
;
3805 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
3808 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
3809 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
3811 This
->updateStateBlock
->set
.textures
[Stage
] = TRUE
;
3812 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
3813 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
3814 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
3816 /* Handle recording of state blocks */
3817 if (This
->isRecordingState
) {
3818 TRACE("Recording... not performing anything\n");
3822 if(oldTexture
== pTexture
) {
3823 TRACE("App is setting the same texture again, nothing to do\n");
3827 /** NOTE: MSDN says that setTexture increases the reference count,
3828 * and the the application nust set the texture back to null (or have a leaky application),
3829 * This means we should pass the refcount up to the parent
3830 *******************************/
3831 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
3832 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
3833 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
3835 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
3836 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
3837 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3838 * so the COLOROP and ALPHAOP have to be dirtified.
3840 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
3841 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
3843 if(bindCount
== 1) {
3844 new->baseTexture
.sampler
= Stage
;
3846 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3850 if (NULL
!= oldTexture
) {
3851 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
3852 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
3854 IWineD3DBaseTexture_Release(oldTexture
);
3855 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
3856 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
3857 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
3860 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
3862 /* Have to do a search for the other sampler(s) where the texture is bound to
3863 * Shouldn't happen as long as apps bind a texture only to one stage
3865 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3866 for(i
= 0; i
< GL_LIMITS(sampler_stages
); i
++) {
3867 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
3868 old
->baseTexture
.sampler
= i
;
3875 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
3877 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3878 * pixel shader is used
3880 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
3881 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3887 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
3888 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3889 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This
, Stage
, ppTexture
);
3891 /* Reject invalid texture units */
3892 if (Stage
>= GL_LIMITS(sampler_stages
)) {
3893 TRACE("Attempt to access invalid texture rejected\n");
3894 return WINED3DERR_INVALIDCALL
;
3896 *ppTexture
=This
->stateBlock
->textures
[Stage
];
3898 IWineD3DBaseTexture_AddRef(*ppTexture
);
3906 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
3907 IWineD3DSurface
**ppBackBuffer
) {
3908 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3909 IWineD3DSwapChain
*swapChain
;
3912 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
3914 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
3915 if (hr
== WINED3D_OK
) {
3916 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
3917 IWineD3DSwapChain_Release(swapChain
);
3919 *ppBackBuffer
= NULL
;
3924 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
3925 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3926 WARN("(%p) : stub, calling idirect3d for now\n", This
);
3927 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
3930 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
3931 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3932 IWineD3DSwapChain
*swapChain
;
3935 if(iSwapChain
> 0) {
3936 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
3937 if (hr
== WINED3D_OK
) {
3938 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
3939 IWineD3DSwapChain_Release(swapChain
);
3941 FIXME("(%p) Error getting display mode\n", This
);
3944 /* Don't read the real display mode,
3945 but return the stored mode instead. X11 can't change the color
3946 depth, and some apps are pretty angry if they SetDisplayMode from
3947 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3949 Also don't relay to the swapchain because with ddraw it's possible
3950 that there isn't a swapchain at all */
3951 pMode
->Width
= This
->ddraw_width
;
3952 pMode
->Height
= This
->ddraw_height
;
3953 pMode
->Format
= This
->ddraw_format
;
3954 pMode
->RefreshRate
= 0;
3961 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
3962 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3963 TRACE("(%p)->(%p)\n", This
, hWnd
);
3965 if(This
->ddraw_fullscreen
) {
3966 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
3967 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
3969 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
3970 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
3974 This
->ddraw_window
= hWnd
;
3978 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
3979 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3980 TRACE("(%p)->(%p)\n", This
, hWnd
);
3982 *hWnd
= This
->ddraw_window
;
3987 * Stateblock related functions
3990 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
3991 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3992 IWineD3DStateBlockImpl
*object
;
3993 HRESULT temp_result
;
3996 TRACE("(%p)\n", This
);
3998 if (This
->isRecordingState
) {
3999 return WINED3DERR_INVALIDCALL
;
4002 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4003 if (NULL
== object
) {
4004 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4005 return E_OUTOFMEMORY
;
4007 TRACE("(%p) created object %p\n", This
, object
);
4008 object
->wineD3DDevice
= This
;
4009 /** FIXME: object->parent = parent; **/
4010 object
->parent
= NULL
;
4011 object
->blockType
= WINED3DSBT_ALL
;
4013 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4015 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4016 list_init(&object
->lightMap
[i
]);
4019 temp_result
= allocate_shader_constants(object
);
4020 if (WINED3D_OK
!= temp_result
)
4023 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4024 This
->updateStateBlock
= object
;
4025 This
->isRecordingState
= TRUE
;
4027 TRACE("(%p) recording stateblock %p\n",This
, object
);
4031 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4032 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4034 if (!This
->isRecordingState
) {
4035 FIXME("(%p) not recording! returning error\n", This
);
4036 *ppStateBlock
= NULL
;
4037 return WINED3DERR_INVALIDCALL
;
4040 *ppStateBlock
= (IWineD3DStateBlock
*)This
->updateStateBlock
;
4041 This
->isRecordingState
= FALSE
;
4042 This
->updateStateBlock
= This
->stateBlock
;
4043 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4044 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4045 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4050 * Scene related functions
4052 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4053 /* At the moment we have no need for any functionality at the beginning
4055 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4056 TRACE("(%p)\n", This
);
4059 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4060 return WINED3DERR_INVALIDCALL
;
4062 This
->inScene
= TRUE
;
4066 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4067 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4068 TRACE("(%p)\n", This
);
4070 if(!This
->inScene
) {
4071 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4072 return WINED3DERR_INVALIDCALL
;
4076 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4078 checkGLcall("glFlush");
4081 This
->inScene
= FALSE
;
4085 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4086 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4087 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4088 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4089 IWineD3DSwapChain
*swapChain
= NULL
;
4091 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4093 TRACE("(%p) Presenting the frame\n", This
);
4095 for(i
= 0 ; i
< swapchains
; i
++) {
4097 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4098 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4099 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4100 IWineD3DSwapChain_Release(swapChain
);
4106 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4107 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4108 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4110 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4111 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4112 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4113 GLbitfield glMask
= 0;
4114 GLboolean old_ztest
;
4115 GLfloat old_z_clear_value
;
4116 GLint old_stencil_clear_value
;
4117 GLfloat old_color_clear_value
[4];
4119 CONST WINED3DRECT
* curRect
;
4121 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This
,
4122 Count
, pRects
, Flags
, Z
, Stencil
);
4126 glEnable(GL_SCISSOR_TEST
);
4127 checkGLcall("glEnable GL_SCISSOR_TEST");
4129 if (Count
> 0 && pRects
) {
4135 /* Only set the values up once, as they are not changing */
4136 if (Flags
& WINED3DCLEAR_STENCIL
) {
4137 glGetIntegerv(GL_STENCIL_CLEAR_VALUE
, &old_stencil_clear_value
);
4138 glClearStencil(Stencil
);
4139 checkGLcall("glClearStencil");
4140 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4141 glStencilMask(0xFFFFFFFF);
4144 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4145 glGetBooleanv(GL_DEPTH_WRITEMASK
, &old_ztest
);
4146 glDepthMask(GL_TRUE
);
4147 glGetFloatv(GL_DEPTH_CLEAR_VALUE
, &old_z_clear_value
);
4149 checkGLcall("glClearDepth");
4150 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4153 if (Flags
& WINED3DCLEAR_TARGET
) {
4154 TRACE("Clearing screen with glClear to color %x\n", Color
);
4155 glGetFloatv(GL_COLOR_CLEAR_VALUE
, old_color_clear_value
);
4156 glClearColor(D3DCOLOR_R(Color
),
4160 checkGLcall("glClearColor");
4162 /* Clear ALL colors! */
4163 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4164 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4167 /* Now process each rect in turn */
4168 for (i
= 0; i
< Count
|| i
== 0; i
++) {
4171 /* Note gl uses lower left, width/height */
4172 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
, curRect
,
4173 curRect
->x1
, curRect
->y1
, curRect
->x2
, curRect
->y2
,
4174 curRect
->x1
, (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
- curRect
->y2
),
4175 curRect
->x2
- curRect
->x1
, curRect
->y2
- curRect
->y1
);
4176 glScissor(curRect
->x1
, (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
- curRect
->y2
),
4177 curRect
->x2
- curRect
->x1
, curRect
->y2
- curRect
->y1
);
4178 checkGLcall("glScissor");
4180 glScissor(This
->stateBlock
->viewport
.X
,
4181 (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
-
4182 (This
->stateBlock
->viewport
.Y
+ This
->stateBlock
->viewport
.Height
)),
4183 This
->stateBlock
->viewport
.Width
,
4184 This
->stateBlock
->viewport
.Height
);
4185 checkGLcall("glScissor");
4188 /* Clear the selected rectangle (or full screen) */
4190 checkGLcall("glClear");
4192 /* Step to the next rectangle */
4193 if (curRect
) curRect
= curRect
+ sizeof(WINED3DRECT
);
4196 /* Restore the old values (why..?) */
4197 if (Flags
& WINED3DCLEAR_STENCIL
) {
4198 glClearStencil(old_stencil_clear_value
);
4199 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4201 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4202 glDepthMask(old_ztest
);
4203 glClearDepth(old_z_clear_value
);
4205 if (Flags
& WINED3DCLEAR_TARGET
) {
4206 glClearColor(old_color_clear_value
[0],
4207 old_color_clear_value
[1],
4208 old_color_clear_value
[2],
4209 old_color_clear_value
[3]);
4210 glColorMask(This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4211 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4212 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4213 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4216 glDisable(GL_SCISSOR_TEST
);
4217 checkGLcall("glDisable");
4220 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4221 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4223 ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->Flags
|= SFLAG_GLDIRTY
;
4230 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4231 UINT PrimitiveCount
) {
4233 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4234 This
->stateBlock
->streamIsUP
= FALSE
;
4236 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4237 debug_d3dprimitivetype(PrimitiveType
),
4238 StartVertex
, PrimitiveCount
);
4240 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4241 This
->stateBlock
->loadBaseVertexIndex
= 0;
4242 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4244 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4245 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4246 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4250 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4251 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4252 WINED3DPRIMITIVETYPE PrimitiveType
,
4253 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4255 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4257 IWineD3DIndexBuffer
*pIB
;
4258 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4260 pIB
= This
->stateBlock
->pIndexData
;
4261 This
->stateBlock
->streamIsUP
= FALSE
;
4263 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
4264 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4265 minIndex
, NumVertices
, startIndex
, primCount
);
4267 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
4268 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
4274 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4275 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4276 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4279 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
4280 idxStride
, ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
4285 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4286 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
4287 UINT VertexStreamZeroStride
) {
4288 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4290 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
4291 debug_d3dprimitivetype(PrimitiveType
),
4292 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4294 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4295 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4296 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4297 This
->stateBlock
->streamIsUP
= TRUE
;
4298 This
->stateBlock
->loadBaseVertexIndex
= 0;
4300 /* TODO: Only mark dirty if drawing from a different UP address */
4301 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4303 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
4304 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
4306 /* MSDN specifies stream zero settings must be set to NULL */
4307 This
->stateBlock
->streamStride
[0] = 0;
4308 This
->stateBlock
->streamSource
[0] = NULL
;
4310 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4311 * the new stream sources or use UP drawing again
4316 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4317 UINT MinVertexIndex
, UINT NumVertices
,
4318 UINT PrimitiveCount
, CONST
void* pIndexData
,
4319 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
4320 UINT VertexStreamZeroStride
) {
4322 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4324 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4325 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4326 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
4327 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4329 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
4335 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4336 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4337 This
->stateBlock
->streamIsUP
= TRUE
;
4338 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4340 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4341 This
->stateBlock
->baseVertexIndex
= 0;
4342 This
->stateBlock
->loadBaseVertexIndex
= 0;
4343 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4344 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4346 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
4348 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4349 This
->stateBlock
->streamSource
[0] = NULL
;
4350 This
->stateBlock
->streamStride
[0] = 0;
4351 This
->stateBlock
->pIndexData
= NULL
;
4352 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4353 * SetStreamSource to specify a vertex buffer
4359 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
4360 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4362 /* Mark the state dirty until we have nicer tracking
4363 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4366 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4367 This
->stateBlock
->baseVertexIndex
= 0;
4368 This
->up_strided
= DrawPrimStrideData
;
4369 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
4370 This
->up_strided
= NULL
;
4373 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4374 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
4375 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4376 HRESULT hr
= WINED3D_OK
;
4377 WINED3DRESOURCETYPE sourceType
;
4378 WINED3DRESOURCETYPE destinationType
;
4381 /* TODO: think about moving the code into IWineD3DBaseTexture */
4383 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
4385 /* verify that the source and destination textures aren't NULL */
4386 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
4387 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4388 This
, pSourceTexture
, pDestinationTexture
);
4389 hr
= WINED3DERR_INVALIDCALL
;
4392 if (pSourceTexture
== pDestinationTexture
) {
4393 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4394 This
, pSourceTexture
, pDestinationTexture
);
4395 hr
= WINED3DERR_INVALIDCALL
;
4397 /* Verify that the source and destination textures are the same type */
4398 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
4399 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
4401 if (sourceType
!= destinationType
) {
4402 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4404 hr
= WINED3DERR_INVALIDCALL
;
4407 /* check that both textures have the identical numbers of levels */
4408 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
4409 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
4410 hr
= WINED3DERR_INVALIDCALL
;
4413 if (WINED3D_OK
== hr
) {
4415 /* Make sure that the destination texture is loaded */
4416 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
4418 /* Update every surface level of the texture */
4419 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
4421 switch (sourceType
) {
4422 case WINED3DRTYPE_TEXTURE
:
4424 IWineD3DSurface
*srcSurface
;
4425 IWineD3DSurface
*destSurface
;
4427 for (i
= 0 ; i
< levels
; ++i
) {
4428 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
4429 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
4430 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
4431 IWineD3DSurface_Release(srcSurface
);
4432 IWineD3DSurface_Release(destSurface
);
4433 if (WINED3D_OK
!= hr
) {
4434 WARN("(%p) : Call to update surface failed\n", This
);
4440 case WINED3DRTYPE_CUBETEXTURE
:
4442 IWineD3DSurface
*srcSurface
;
4443 IWineD3DSurface
*destSurface
;
4444 WINED3DCUBEMAP_FACES faceType
;
4446 for (i
= 0 ; i
< levels
; ++i
) {
4447 /* Update each cube face */
4448 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
4449 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
4450 if (WINED3D_OK
!= hr
) {
4451 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
4453 TRACE("Got srcSurface %p\n", srcSurface
);
4455 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
4456 if (WINED3D_OK
!= hr
) {
4457 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
4459 TRACE("Got desrSurface %p\n", destSurface
);
4461 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
4462 IWineD3DSurface_Release(srcSurface
);
4463 IWineD3DSurface_Release(destSurface
);
4464 if (WINED3D_OK
!= hr
) {
4465 WARN("(%p) : Call to update surface failed\n", This
);
4472 #if 0 /* TODO: Add support for volume textures */
4473 case WINED3DRTYPE_VOLUMETEXTURE
:
4475 IWineD3DVolume srcVolume
= NULL
;
4476 IWineD3DSurface destVolume
= NULL
;
4478 for (i
= 0 ; i
< levels
; ++i
) {
4479 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
4480 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
4481 hr
= IWineD3DFoo_UpdateVolume(iface
, srcVolume
, NULL
, destVolume
, NULL
);
4482 IWineD3DVolume_Release(srcSurface
);
4483 IWineD3DVolume_Release(destSurface
);
4484 if (WINED3D_OK
!= hr
) {
4485 WARN("(%p) : Call to update volume failed\n", This
);
4493 FIXME("(%p) : Unsupported source and destination type\n", This
);
4494 hr
= WINED3DERR_INVALIDCALL
;
4501 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
4502 IWineD3DSwapChain
*swapChain
;
4504 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4505 if(hr
== WINED3D_OK
) {
4506 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
4507 IWineD3DSwapChain_Release(swapChain
);
4512 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
4513 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4514 /* return a sensible default */
4516 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4517 FIXME("(%p) : stub\n", This
);
4521 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
4522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4524 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4525 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
4526 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4527 return WINED3DERR_INVALIDCALL
;
4529 for (j
= 0; j
< 256; ++j
) {
4530 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
4531 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
4532 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
4533 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
4535 TRACE("(%p) : returning\n", This
);
4539 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
4540 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4542 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4543 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
4544 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4545 return WINED3DERR_INVALIDCALL
;
4547 for (j
= 0; j
< 256; ++j
) {
4548 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
4549 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
4550 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
4551 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
4553 TRACE("(%p) : returning\n", This
);
4557 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
4558 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4559 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4560 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
4561 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4562 return WINED3DERR_INVALIDCALL
;
4564 /*TODO: stateblocks */
4565 This
->currentPalette
= PaletteNumber
;
4566 TRACE("(%p) : returning\n", This
);
4570 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
4571 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4572 if (PaletteNumber
== NULL
) {
4573 WARN("(%p) : returning Invalid Call\n", This
);
4574 return WINED3DERR_INVALIDCALL
;
4576 /*TODO: stateblocks */
4577 *PaletteNumber
= This
->currentPalette
;
4578 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
4582 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
4583 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4584 static BOOL showFixmes
= TRUE
;
4586 FIXME("(%p) : stub\n", This
);
4590 This
->softwareVertexProcessing
= bSoftware
;
4595 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
4596 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4597 static BOOL showFixmes
= TRUE
;
4599 FIXME("(%p) : stub\n", This
);
4602 return This
->softwareVertexProcessing
;
4606 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
4607 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4608 IWineD3DSwapChain
*swapChain
;
4611 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
4613 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4614 if(hr
== WINED3D_OK
){
4615 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
4616 IWineD3DSwapChain_Release(swapChain
);
4618 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
4624 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
4625 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4626 static BOOL showfixmes
= TRUE
;
4627 if(nSegments
!= 0.0f
) {
4629 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
4636 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
4637 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4638 static BOOL showfixmes
= TRUE
;
4640 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
4646 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
4647 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4648 /** TODO: remove casts to IWineD3DSurfaceImpl
4649 * NOTE: move code to surface to accomplish this
4650 ****************************************/
4651 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
4652 int srcWidth
, srcHeight
;
4653 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
4654 WINED3DFORMAT destFormat
, srcFormat
;
4656 int srcLeft
, destLeft
, destTop
;
4657 WINED3DPOOL srcPool
, destPool
;
4659 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4660 glDescriptor
*glDescription
= NULL
;
4661 GLenum textureDimensions
= GL_TEXTURE_2D
;
4662 IWineD3DBaseTexture
*baseTexture
;
4664 WINED3DSURFACE_DESC winedesc
;
4666 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
4667 memset(&winedesc
, 0, sizeof(winedesc
));
4668 winedesc
.Width
= &srcSurfaceWidth
;
4669 winedesc
.Height
= &srcSurfaceHeight
;
4670 winedesc
.Pool
= &srcPool
;
4671 winedesc
.Format
= &srcFormat
;
4673 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
4675 winedesc
.Width
= &destSurfaceWidth
;
4676 winedesc
.Height
= &destSurfaceHeight
;
4677 winedesc
.Pool
= &destPool
;
4678 winedesc
.Format
= &destFormat
;
4679 winedesc
.Size
= &destSize
;
4681 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
4683 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
4684 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
4685 return WINED3DERR_INVALIDCALL
;
4688 if (destFormat
== WINED3DFMT_UNKNOWN
) {
4689 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
4690 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
4692 /* Get the update surface description */
4693 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
4696 /* Make sure the surface is loaded and up to date */
4697 IWineD3DSurface_PreLoad(pDestinationSurface
);
4699 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
4703 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4704 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
4705 srcHeight
= pSourceRect
? pSourceRect
->top
- pSourceRect
->bottom
: srcSurfaceHeight
;
4706 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
4707 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
4708 destTop
= pDestPoint
? pDestPoint
->y
: 0;
4711 /* This function doesn't support compressed textures
4712 the pitch is just bytesPerPixel * width */
4713 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
4714 rowoffset
= (srcSurfaceWidth
- srcWidth
) * pSrcSurface
->bytesPerPixel
;
4715 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
4716 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4718 /* TODO DXT formats */
4720 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
4721 offset
+= pSourceRect
->top
* srcWidth
* pSrcSurface
->bytesPerPixel
;
4723 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4725 ,glDescription
->level
4730 ,glDescription
->glFormat
4731 ,glDescription
->glType
4732 ,IWineD3DSurface_GetData(pSourceSurface
)
4736 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
4738 /* need to lock the surface to get the data */
4739 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4742 /* TODO: Cube and volume support */
4744 /* not a whole row so we have to do it a line at a time */
4747 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4748 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
4750 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
4752 glTexSubImage2D(glDescription
->target
4753 ,glDescription
->level
4758 ,glDescription
->glFormat
4759 ,glDescription
->glType
4760 ,data
/* could be quicker using */
4765 } else { /* Full width, so just write out the whole texture */
4767 if (WINED3DFMT_DXT1
== destFormat
||
4768 WINED3DFMT_DXT2
== destFormat
||
4769 WINED3DFMT_DXT3
== destFormat
||
4770 WINED3DFMT_DXT4
== destFormat
||
4771 WINED3DFMT_DXT5
== destFormat
) {
4772 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
4773 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
4774 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4775 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4776 } if (destFormat
!= srcFormat
) {
4777 FIXME("Updating mixed format compressed texture is not curretly support\n");
4779 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
4780 glDescription
->level
,
4781 glDescription
->glFormatInternal
,
4786 IWineD3DSurface_GetData(pSourceSurface
));
4789 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4794 glTexSubImage2D(glDescription
->target
4795 ,glDescription
->level
4800 ,glDescription
->glFormat
4801 ,glDescription
->glType
4802 ,IWineD3DSurface_GetData(pSourceSurface
)
4806 checkGLcall("glTexSubImage2D");
4807 ((IWineD3DSurfaceImpl
*)pDestinationSurface
)->Flags
|= SFLAG_GLDIRTY
;
4809 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4810 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4811 * surface bigger than it needs to be hmm.. */
4812 if (WINED3D_OK
== IWineD3DSurface_GetContainer(pDestinationSurface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
)) {
4813 textureDimensions
= IWineD3DBaseTexture_GetTextureDimensions(baseTexture
);
4814 IWineD3DBaseTexture_Release(baseTexture
);
4817 glDisable(textureDimensions
); /* This needs to be managed better.... */
4823 /* Implementation details at http://developer.nvidia.com/attach/6494
4825 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4826 hmm.. no longer supported use
4827 OpenGL evaluators or tessellate surfaces within your application.
4830 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4831 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
4832 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4833 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
4834 FIXME("(%p) : Stub\n", This
);
4839 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4840 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
4841 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4842 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
4843 FIXME("(%p) : Stub\n", This
);
4847 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
4848 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4849 TRACE("(%p) Handle(%d)\n", This
, Handle
);
4850 FIXME("(%p) : Stub\n", This
);
4854 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
4855 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4856 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
4858 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This
, pSurface
, pRect
, color
);
4860 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
4861 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4862 return WINED3DERR_INVALIDCALL
;
4865 /* Just forward this to the DirectDraw blitting engine */
4866 memset(&BltFx
, 0, sizeof(BltFx
));
4867 BltFx
.dwSize
= sizeof(BltFx
);
4868 BltFx
.u5
.dwFillColor
= color
;
4869 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, DDBLT_COLORFILL
, &BltFx
);
4872 /* rendertarget and deptth stencil functions */
4873 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
4874 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4876 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
4877 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
4878 return WINED3DERR_INVALIDCALL
;
4881 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
4882 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
4883 /* Note inc ref on returned surface */
4884 if(*ppRenderTarget
!= NULL
)
4885 IWineD3DSurface_AddRef(*ppRenderTarget
);
4889 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
4890 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4891 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
4892 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
4893 IWineD3DSwapChainImpl
*Swapchain
;
4896 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
4898 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
4899 if(hr
!= WINED3D_OK
) {
4900 ERR("Can't get the swapchain\n");
4904 /* Make sure to release the swapchain */
4905 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
4907 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
4908 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4909 return WINED3DERR_INVALIDCALL
;
4911 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
4912 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4913 return WINED3DERR_INVALIDCALL
;
4916 if(Swapchain
->frontBuffer
!= Front
) {
4917 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
4919 if(Swapchain
->frontBuffer
)
4920 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
4921 Swapchain
->frontBuffer
= Front
;
4923 if(Swapchain
->frontBuffer
) {
4924 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
4928 if(Back
&& !Swapchain
->backBuffer
) {
4929 /* We need memory for the back buffer array - only one back buffer this way */
4930 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
4931 if(!Swapchain
->backBuffer
) {
4932 ERR("Out of memory\n");
4933 return E_OUTOFMEMORY
;
4937 if(Swapchain
->backBuffer
[0] != Back
) {
4938 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
4940 if(!Swapchain
->backBuffer
[0]) {
4941 /* GL was told to draw to the front buffer at creation,
4944 glDrawBuffer(GL_BACK
);
4945 checkGLcall("glDrawBuffer(GL_BACK)");
4946 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4947 Swapchain
->presentParms
.BackBufferCount
= 1;
4949 /* That makes problems - disable for now */
4950 /* glDrawBuffer(GL_FRONT); */
4951 checkGLcall("glDrawBuffer(GL_FRONT)");
4952 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4953 Swapchain
->presentParms
.BackBufferCount
= 0;
4957 if(Swapchain
->backBuffer
[0])
4958 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
4959 Swapchain
->backBuffer
[0] = Back
;
4961 if(Swapchain
->backBuffer
[0]) {
4962 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
4964 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
4972 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
4973 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4974 *ppZStencilSurface
= This
->depthStencilBuffer
;
4975 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
4977 if(*ppZStencilSurface
!= NULL
) {
4978 /* Note inc ref on returned surface */
4979 IWineD3DSurface_AddRef(*ppZStencilSurface
);
4984 static void bind_fbo(IWineD3DDevice
*iface
) {
4985 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4988 GL_EXTCALL(glGenFramebuffersEXT(1, &This
->fbo
));
4989 checkGLcall("glGenFramebuffersEXT()");
4991 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, This
->fbo
));
4992 checkGLcall("glBindFramebuffer()");
4995 /* TODO: Handle stencil attachments */
4996 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
4997 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4998 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
5000 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
5004 if (depth_stencil_impl
) {
5005 GLenum texttarget
, target
;
5006 GLint old_binding
= 0;
5008 IWineD3DSurface_PreLoad(depth_stencil
);
5009 texttarget
= depth_stencil_impl
->glDescription
.target
;
5010 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5012 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5013 glBindTexture(target
, depth_stencil_impl
->glDescription
.textureName
);
5014 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5015 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5016 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5017 glBindTexture(target
, old_binding
);
5019 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
, depth_stencil_impl
->glDescription
.textureName
, 0));
5020 checkGLcall("glFramebufferTexture2DEXT()");
5022 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
5023 checkGLcall("glFramebufferTexture2DEXT()");
5026 if (!This
->render_offscreen
) {
5027 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5028 checkGLcall("glBindFramebuffer()");
5032 void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
5033 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5034 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
5036 if (idx
>= GL_LIMITS(buffers
)) {
5037 ERR("%p : Trying to set render target %d, but only %d supported\n", This
, idx
, GL_LIMITS(buffers
));
5043 GLenum texttarget
, target
;
5044 GLint old_binding
= 0;
5046 IWineD3DSurface_PreLoad(render_target
);
5047 texttarget
= rtimpl
->glDescription
.target
;
5048 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5050 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5051 glBindTexture(target
, rtimpl
->glDescription
.textureName
);
5052 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
5053 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
5054 glBindTexture(target
, old_binding
);
5056 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
, rtimpl
->glDescription
.textureName
, 0));
5057 checkGLcall("glFramebufferTexture2DEXT()");
5059 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
5061 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
5062 checkGLcall("glFramebufferTexture2DEXT()");
5064 This
->draw_buffers
[idx
] = GL_NONE
;
5067 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
5068 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
5069 checkGLcall("glDrawBuffers()");
5072 if (!This
->render_offscreen
) {
5073 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5074 checkGLcall("glBindFramebuffer()");
5078 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
5079 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5080 WINED3DVIEWPORT viewport
;
5082 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5084 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5085 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5086 return WINED3DERR_INVALIDCALL
;
5089 /* MSDN says that null disables the render target
5090 but a device must always be associated with a render target
5091 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5093 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5096 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5097 FIXME("Trying to set render target 0 to NULL\n");
5098 return WINED3DERR_INVALIDCALL
;
5100 if (pRenderTarget
&& !((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
5101 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
);
5102 return WINED3DERR_INVALIDCALL
;
5105 /* If we are trying to set what we already have, don't bother */
5106 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5107 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5110 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5111 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5112 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5114 /* Render target 0 is special */
5115 if(RenderTargetIndex
== 0) {
5116 /* Finally, reset the viewport as the MSDN states. */
5117 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5118 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5121 viewport
.MaxZ
= 1.0f
;
5122 viewport
.MinZ
= 0.0f
;
5123 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
5125 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5127 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5128 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5130 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
5132 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5133 set_render_target_fbo(iface
, RenderTargetIndex
, pRenderTarget
);
5138 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5139 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5140 HRESULT hr
= WINED3D_OK
;
5141 IWineD3DSurface
*tmp
;
5143 TRACE("(%p) Swapping z-buffer\n",This
);
5145 if (pNewZStencil
== This
->stencilBufferTarget
) {
5146 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5148 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5149 * depending on the renter target implementation being used.
5150 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5151 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5152 * stencil buffer and incure an extra memory overhead
5153 ******************************************************/
5156 tmp
= This
->stencilBufferTarget
;
5157 This
->stencilBufferTarget
= pNewZStencil
;
5158 /* should we be calling the parent or the wined3d surface? */
5159 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5160 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5162 /** TODO: glEnable/glDisable on depth/stencil depending on
5163 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5164 **********************************************************/
5165 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5166 set_depth_stencil_fbo(iface
, pNewZStencil
);
5173 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
5174 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
5175 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5176 /* TODO: the use of Impl is deprecated. */
5177 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
5179 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
5181 /* some basic validation checks */
5182 if(This
->cursorTexture
) {
5184 glDeleteTextures(1, &This
->cursorTexture
);
5186 This
->cursorTexture
= 0;
5190 /* MSDN: Cursor must be A8R8G8B8 */
5191 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
5192 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
5193 return WINED3DERR_INVALIDCALL
;
5196 /* MSDN: Cursor must be smaller than the display mode */
5197 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
5198 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
5199 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
);
5200 return WINED3DERR_INVALIDCALL
;
5203 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5204 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5205 * Texture and Blitting code to draw the cursor
5207 pSur
->Flags
|= SFLAG_FORCELOAD
;
5208 IWineD3DSurface_PreLoad(pCursorBitmap
);
5209 pSur
->Flags
&= ~SFLAG_FORCELOAD
;
5210 /* Do not store the surface's pointer because the application may release
5211 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5212 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5214 This
->cursorTexture
= pSur
->glDescription
.textureName
;
5215 This
->cursorWidth
= pSur
->currentDesc
.Width
;
5216 This
->cursorHeight
= pSur
->currentDesc
.Height
;
5217 pSur
->glDescription
.textureName
= 0; /* Prevent the texture from being changed or deleted */
5220 This
->xHotSpot
= XHotSpot
;
5221 This
->yHotSpot
= YHotSpot
;
5225 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
5226 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5227 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
5229 This
->xScreenSpace
= XScreenSpace
;
5230 This
->yScreenSpace
= YScreenSpace
;
5236 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
5237 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5238 BOOL oldVisible
= This
->bCursorVisible
;
5239 TRACE("(%p) : visible(%d)\n", This
, bShow
);
5241 if(This
->cursorTexture
)
5242 This
->bCursorVisible
= bShow
;
5247 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
5248 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5249 TRACE("(%p) : state (%u)\n", This
, This
->state
);
5250 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5251 switch (This
->state
) {
5254 case WINED3DERR_DEVICELOST
:
5256 ResourceList
*resourceList
= This
->resources
;
5257 while (NULL
!= resourceList
) {
5258 if (((IWineD3DResourceImpl
*)resourceList
->resource
)->resource
.pool
== WINED3DPOOL_DEFAULT
/* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5259 return WINED3DERR_DEVICENOTRESET
;
5260 resourceList
= resourceList
->next
;
5262 return WINED3DERR_DEVICELOST
;
5264 case WINED3DERR_DRIVERINTERNALERROR
:
5265 return WINED3DERR_DRIVERINTERNALERROR
;
5269 return WINED3DERR_DRIVERINTERNALERROR
;
5273 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
5274 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5275 /** FIXME: Resource tracking needs to be done,
5276 * The closes we can do to this is set the priorities of all managed textures low
5277 * and then reset them.
5278 ***********************************************************/
5279 FIXME("(%p) : stub\n", This
);
5283 void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
5284 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
5286 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5287 if(surface
->Flags
& SFLAG_DIBSECTION
) {
5288 /* Release the DC */
5289 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
5290 DeleteDC(surface
->hDC
);
5291 /* Release the DIB section */
5292 DeleteObject(surface
->dib
.DIBsection
);
5293 surface
->dib
.bitmap_data
= NULL
;
5294 surface
->resource
.allocatedMemory
= NULL
;
5295 surface
->Flags
&= ~SFLAG_DIBSECTION
;
5297 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
5298 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
5299 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
5300 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
5301 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
5303 surface
->pow2Width
= surface
->pow2Height
= 1;
5304 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
5305 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
5307 if(surface
->glDescription
.textureName
) {
5309 glDeleteTextures(1, &surface
->glDescription
.textureName
);
5311 surface
->glDescription
.textureName
= 0;
5313 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
5314 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
5315 surface
->Flags
|= SFLAG_NONPOW2
;
5317 surface
->Flags
&= ~SFLAG_NONPOW2
;
5319 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
5320 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
5323 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
5324 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5325 IWineD3DSwapChainImpl
*swapchain
;
5327 BOOL DisplayModeChanged
= FALSE
;
5328 WINED3DDISPLAYMODE mode
;
5329 TRACE("(%p)\n", This
);
5331 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
5333 ERR("Failed to get the first implicit swapchain\n");
5337 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5338 * on an existing gl context, so there's no real need for recreation.
5340 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5342 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5344 TRACE("New params:\n");
5345 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
5346 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
5347 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
5348 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
5349 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
5350 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
5351 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
5352 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
5353 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
5354 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
5355 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
5356 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
5357 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
5359 /* No special treatment of these parameters. Just store them */
5360 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
5361 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
5362 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
5363 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
5365 /* What to do about these? */
5366 if(pPresentationParameters
->BackBufferCount
!= 0 &&
5367 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
5368 ERR("Cannot change the back buffer count yet\n");
5370 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
5371 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
5372 ERR("Cannot change the back buffer format yet\n");
5374 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
5375 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
5376 ERR("Cannot change the device window yet\n");
5378 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
5379 ERR("What do do about a changed auto depth stencil parameter?\n");
5382 if(pPresentationParameters
->Windowed
) {
5383 mode
.Width
= swapchain
->orig_width
;
5384 mode
.Height
= swapchain
->orig_height
;
5385 mode
.RefreshRate
= 0;
5386 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
5388 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
5389 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
5390 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
5391 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
5394 /* Should Width == 800 && Height == 0 set 800x600? */
5395 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
5396 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
5397 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
5404 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
5405 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
5409 if(!pPresentationParameters
->Windowed
) {
5410 DisplayModeChanged
= TRUE
;
5412 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
5413 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
5415 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
5416 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
5417 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
5420 /* Now set the new viewport */
5421 IWineD3DDevice_SetViewport(iface
, &vp
);
5424 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
5425 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
5426 DisplayModeChanged
) {
5428 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5429 if(!pPresentationParameters
->Windowed
) {
5430 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
5433 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
5435 /* Switching out of fullscreen mode? First set the original res, then change the window */
5436 if(pPresentationParameters
->Windowed
) {
5437 IWineD3DDevice_SetFullscreen(iface
, FALSE
);
5439 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
5442 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5446 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
5447 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5448 /** FIXME: always true at the moment **/
5449 if(!bEnableDialogs
) {
5450 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
5456 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
5457 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5458 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
5460 *pParameters
= This
->createParms
;
5464 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
5465 IWineD3DSwapChain
*swapchain
;
5466 HRESULT hrc
= WINED3D_OK
;
5468 TRACE("Relaying to swapchain\n");
5470 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
5471 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
5472 IWineD3DSwapChain_Release(swapchain
);
5477 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
5478 IWineD3DSwapChain
*swapchain
;
5479 HRESULT hrc
= WINED3D_OK
;
5481 TRACE("Relaying to swapchain\n");
5483 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
5484 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
5485 IWineD3DSwapChain_Release(swapchain
);
5491 /** ********************************************************
5492 * Notification functions
5493 ** ********************************************************/
5494 /** This function must be called in the release of a resource when ref == 0,
5495 * the contents of resource must still be correct,
5496 * any handels to other resource held by the caller must be closed
5497 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5498 *****************************************************/
5499 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
5500 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5501 ResourceList
* resourceList
;
5503 TRACE("(%p) : resource %p\n", This
, resource
);
5505 EnterCriticalSection(&resourceStoreCriticalSection
);
5507 /* add a new texture to the frot of the linked list */
5508 resourceList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ResourceList
));
5509 resourceList
->resource
= resource
;
5511 /* Get the old head */
5512 resourceList
->next
= This
->resources
;
5514 This
->resources
= resourceList
;
5515 TRACE("Added resource %p with element %p pointing to %p\n", resource
, resourceList
, resourceList
->next
);
5518 LeaveCriticalSection(&resourceStoreCriticalSection
);
5523 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
5524 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5525 ResourceList
* resourceList
= NULL
;
5526 ResourceList
* previousResourceList
= NULL
;
5528 TRACE("(%p) : resource %p\n", This
, resource
);
5531 EnterCriticalSection(&resourceStoreCriticalSection
);
5533 resourceList
= This
->resources
;
5535 while (resourceList
!= NULL
) {
5536 if(resourceList
->resource
== resource
) break;
5537 previousResourceList
= resourceList
;
5538 resourceList
= resourceList
->next
;
5541 if (resourceList
== NULL
) {
5542 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource
);
5544 LeaveCriticalSection(&resourceStoreCriticalSection
);
5548 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList
->resource
, resourceList
, resourceList
->next
, previousResourceList
);
5550 /* make sure we don't leave a hole in the list */
5551 if (previousResourceList
!= NULL
) {
5552 previousResourceList
->next
= resourceList
->next
;
5554 This
->resources
= resourceList
->next
;
5558 LeaveCriticalSection(&resourceStoreCriticalSection
);
5564 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
5565 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5568 TRACE("(%p) : resource %p\n", This
, resource
);
5569 switch(IWineD3DResource_GetType(resource
)){
5570 case WINED3DRTYPE_SURFACE
:
5571 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5573 case WINED3DRTYPE_TEXTURE
:
5574 case WINED3DRTYPE_CUBETEXTURE
:
5575 case WINED3DRTYPE_VOLUMETEXTURE
:
5576 for (counter
= 0; counter
< GL_LIMITS(sampler_stages
); counter
++) {
5577 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
5578 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
5579 This
->stateBlock
->textures
[counter
] = NULL
;
5581 if (This
->updateStateBlock
!= This
->stateBlock
){
5582 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
5583 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
5584 This
->updateStateBlock
->textures
[counter
] = NULL
;
5589 case WINED3DRTYPE_VOLUME
:
5590 /* TODO: nothing really? */
5592 case WINED3DRTYPE_VERTEXBUFFER
:
5593 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5596 TRACE("Cleaning up stream pointers\n");
5598 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
5599 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5600 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5602 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
5603 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
5604 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
5605 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
5606 /* Set changed flag? */
5609 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) */
5610 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
5611 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
5612 This
->stateBlock
->streamSource
[streamNumber
] = 0;
5615 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5616 else { /* This shouldn't happen */
5617 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5624 case WINED3DRTYPE_INDEXBUFFER
:
5625 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5626 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
5627 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
5628 This
->updateStateBlock
->pIndexData
= NULL
;
5631 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
5632 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
5633 This
->stateBlock
->pIndexData
= NULL
;
5639 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
5644 /* Remove the resoruce from the resourceStore */
5645 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
5647 TRACE("Resource released\n");
5651 /**********************************************************
5652 * IWineD3DDevice VTbl follows
5653 **********************************************************/
5655 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
5657 /*** IUnknown methods ***/
5658 IWineD3DDeviceImpl_QueryInterface
,
5659 IWineD3DDeviceImpl_AddRef
,
5660 IWineD3DDeviceImpl_Release
,
5661 /*** IWineD3DDevice methods ***/
5662 IWineD3DDeviceImpl_GetParent
,
5663 /*** Creation methods**/
5664 IWineD3DDeviceImpl_CreateVertexBuffer
,
5665 IWineD3DDeviceImpl_CreateIndexBuffer
,
5666 IWineD3DDeviceImpl_CreateStateBlock
,
5667 IWineD3DDeviceImpl_CreateSurface
,
5668 IWineD3DDeviceImpl_CreateTexture
,
5669 IWineD3DDeviceImpl_CreateVolumeTexture
,
5670 IWineD3DDeviceImpl_CreateVolume
,
5671 IWineD3DDeviceImpl_CreateCubeTexture
,
5672 IWineD3DDeviceImpl_CreateQuery
,
5673 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
5674 IWineD3DDeviceImpl_CreateVertexDeclaration
,
5675 IWineD3DDeviceImpl_CreateVertexShader
,
5676 IWineD3DDeviceImpl_CreatePixelShader
,
5677 IWineD3DDeviceImpl_CreatePalette
,
5678 /*** Odd functions **/
5679 IWineD3DDeviceImpl_Init3D
,
5680 IWineD3DDeviceImpl_Uninit3D
,
5681 IWineD3DDeviceImpl_SetFullscreen
,
5682 IWineD3DDeviceImpl_EvictManagedResources
,
5683 IWineD3DDeviceImpl_GetAvailableTextureMem
,
5684 IWineD3DDeviceImpl_GetBackBuffer
,
5685 IWineD3DDeviceImpl_GetCreationParameters
,
5686 IWineD3DDeviceImpl_GetDeviceCaps
,
5687 IWineD3DDeviceImpl_GetDirect3D
,
5688 IWineD3DDeviceImpl_GetDisplayMode
,
5689 IWineD3DDeviceImpl_SetDisplayMode
,
5690 IWineD3DDeviceImpl_GetHWND
,
5691 IWineD3DDeviceImpl_SetHWND
,
5692 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
5693 IWineD3DDeviceImpl_GetRasterStatus
,
5694 IWineD3DDeviceImpl_GetSwapChain
,
5695 IWineD3DDeviceImpl_Reset
,
5696 IWineD3DDeviceImpl_SetDialogBoxMode
,
5697 IWineD3DDeviceImpl_SetCursorProperties
,
5698 IWineD3DDeviceImpl_SetCursorPosition
,
5699 IWineD3DDeviceImpl_ShowCursor
,
5700 IWineD3DDeviceImpl_TestCooperativeLevel
,
5701 /*** Getters and setters **/
5702 IWineD3DDeviceImpl_SetClipPlane
,
5703 IWineD3DDeviceImpl_GetClipPlane
,
5704 IWineD3DDeviceImpl_SetClipStatus
,
5705 IWineD3DDeviceImpl_GetClipStatus
,
5706 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
5707 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
5708 IWineD3DDeviceImpl_SetDepthStencilSurface
,
5709 IWineD3DDeviceImpl_GetDepthStencilSurface
,
5710 IWineD3DDeviceImpl_SetFVF
,
5711 IWineD3DDeviceImpl_GetFVF
,
5712 IWineD3DDeviceImpl_SetGammaRamp
,
5713 IWineD3DDeviceImpl_GetGammaRamp
,
5714 IWineD3DDeviceImpl_SetIndices
,
5715 IWineD3DDeviceImpl_GetIndices
,
5716 IWineD3DDeviceImpl_SetBasevertexIndex
,
5717 IWineD3DDeviceImpl_SetLight
,
5718 IWineD3DDeviceImpl_GetLight
,
5719 IWineD3DDeviceImpl_SetLightEnable
,
5720 IWineD3DDeviceImpl_GetLightEnable
,
5721 IWineD3DDeviceImpl_SetMaterial
,
5722 IWineD3DDeviceImpl_GetMaterial
,
5723 IWineD3DDeviceImpl_SetNPatchMode
,
5724 IWineD3DDeviceImpl_GetNPatchMode
,
5725 IWineD3DDeviceImpl_SetPaletteEntries
,
5726 IWineD3DDeviceImpl_GetPaletteEntries
,
5727 IWineD3DDeviceImpl_SetPixelShader
,
5728 IWineD3DDeviceImpl_GetPixelShader
,
5729 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
5730 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
5731 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
5732 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
5733 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
5734 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
5735 IWineD3DDeviceImpl_SetRenderState
,
5736 IWineD3DDeviceImpl_GetRenderState
,
5737 IWineD3DDeviceImpl_SetRenderTarget
,
5738 IWineD3DDeviceImpl_GetRenderTarget
,
5739 IWineD3DDeviceImpl_SetFrontBackBuffers
,
5740 IWineD3DDeviceImpl_SetSamplerState
,
5741 IWineD3DDeviceImpl_GetSamplerState
,
5742 IWineD3DDeviceImpl_SetScissorRect
,
5743 IWineD3DDeviceImpl_GetScissorRect
,
5744 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
5745 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
5746 IWineD3DDeviceImpl_SetStreamSource
,
5747 IWineD3DDeviceImpl_GetStreamSource
,
5748 IWineD3DDeviceImpl_SetStreamSourceFreq
,
5749 IWineD3DDeviceImpl_GetStreamSourceFreq
,
5750 IWineD3DDeviceImpl_SetTexture
,
5751 IWineD3DDeviceImpl_GetTexture
,
5752 IWineD3DDeviceImpl_SetTextureStageState
,
5753 IWineD3DDeviceImpl_GetTextureStageState
,
5754 IWineD3DDeviceImpl_SetTransform
,
5755 IWineD3DDeviceImpl_GetTransform
,
5756 IWineD3DDeviceImpl_SetVertexDeclaration
,
5757 IWineD3DDeviceImpl_GetVertexDeclaration
,
5758 IWineD3DDeviceImpl_SetVertexShader
,
5759 IWineD3DDeviceImpl_GetVertexShader
,
5760 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
5761 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
5762 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
5763 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
5764 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
5765 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
5766 IWineD3DDeviceImpl_SetViewport
,
5767 IWineD3DDeviceImpl_GetViewport
,
5768 IWineD3DDeviceImpl_MultiplyTransform
,
5769 IWineD3DDeviceImpl_ValidateDevice
,
5770 IWineD3DDeviceImpl_ProcessVertices
,
5771 /*** State block ***/
5772 IWineD3DDeviceImpl_BeginStateBlock
,
5773 IWineD3DDeviceImpl_EndStateBlock
,
5774 /*** Scene management ***/
5775 IWineD3DDeviceImpl_BeginScene
,
5776 IWineD3DDeviceImpl_EndScene
,
5777 IWineD3DDeviceImpl_Present
,
5778 IWineD3DDeviceImpl_Clear
,
5780 IWineD3DDeviceImpl_DrawPrimitive
,
5781 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
5782 IWineD3DDeviceImpl_DrawPrimitiveUP
,
5783 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
5784 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
5785 IWineD3DDeviceImpl_DrawRectPatch
,
5786 IWineD3DDeviceImpl_DrawTriPatch
,
5787 IWineD3DDeviceImpl_DeletePatch
,
5788 IWineD3DDeviceImpl_ColorFill
,
5789 IWineD3DDeviceImpl_UpdateTexture
,
5790 IWineD3DDeviceImpl_UpdateSurface
,
5791 IWineD3DDeviceImpl_GetFrontBufferData
,
5792 /*** object tracking ***/
5793 IWineD3DDeviceImpl_ResourceReleased
5797 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
5798 WINED3DRS_ALPHABLENDENABLE
,
5799 WINED3DRS_ALPHAFUNC
,
5800 WINED3DRS_ALPHAREF
,
5801 WINED3DRS_ALPHATESTENABLE
,
5803 WINED3DRS_COLORWRITEENABLE
,
5804 WINED3DRS_DESTBLEND
,
5805 WINED3DRS_DITHERENABLE
,
5806 WINED3DRS_FILLMODE
,
5807 WINED3DRS_FOGDENSITY
,
5809 WINED3DRS_FOGSTART
,
5810 WINED3DRS_LASTPIXEL
,
5811 WINED3DRS_SHADEMODE
,
5812 WINED3DRS_SRCBLEND
,
5813 WINED3DRS_STENCILENABLE
,
5814 WINED3DRS_STENCILFAIL
,
5815 WINED3DRS_STENCILFUNC
,
5816 WINED3DRS_STENCILMASK
,
5817 WINED3DRS_STENCILPASS
,
5818 WINED3DRS_STENCILREF
,
5819 WINED3DRS_STENCILWRITEMASK
,
5820 WINED3DRS_STENCILZFAIL
,
5821 WINED3DRS_TEXTUREFACTOR
,
5832 WINED3DRS_ZWRITEENABLE
5835 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
5836 WINED3DTSS_ADDRESSW
,
5837 WINED3DTSS_ALPHAARG0
,
5838 WINED3DTSS_ALPHAARG1
,
5839 WINED3DTSS_ALPHAARG2
,
5840 WINED3DTSS_ALPHAOP
,
5841 WINED3DTSS_BUMPENVLOFFSET
,
5842 WINED3DTSS_BUMPENVLSCALE
,
5843 WINED3DTSS_BUMPENVMAT00
,
5844 WINED3DTSS_BUMPENVMAT01
,
5845 WINED3DTSS_BUMPENVMAT10
,
5846 WINED3DTSS_BUMPENVMAT11
,
5847 WINED3DTSS_COLORARG0
,
5848 WINED3DTSS_COLORARG1
,
5849 WINED3DTSS_COLORARG2
,
5850 WINED3DTSS_COLOROP
,
5851 WINED3DTSS_RESULTARG
,
5852 WINED3DTSS_TEXCOORDINDEX
,
5853 WINED3DTSS_TEXTURETRANSFORMFLAGS
5856 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
5857 WINED3DSAMP_ADDRESSU
,
5858 WINED3DSAMP_ADDRESSV
,
5859 WINED3DSAMP_ADDRESSW
,
5860 WINED3DSAMP_BORDERCOLOR
,
5861 WINED3DSAMP_MAGFILTER
,
5862 WINED3DSAMP_MINFILTER
,
5863 WINED3DSAMP_MIPFILTER
,
5864 WINED3DSAMP_MIPMAPLODBIAS
,
5865 WINED3DSAMP_MAXMIPLEVEL
,
5866 WINED3DSAMP_MAXANISOTROPY
,
5867 WINED3DSAMP_SRGBTEXTURE
,
5868 WINED3DSAMP_ELEMENTINDEX
5871 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
5873 WINED3DRS_AMBIENTMATERIALSOURCE
,
5874 WINED3DRS_CLIPPING
,
5875 WINED3DRS_CLIPPLANEENABLE
,
5876 WINED3DRS_COLORVERTEX
,
5877 WINED3DRS_DIFFUSEMATERIALSOURCE
,
5878 WINED3DRS_EMISSIVEMATERIALSOURCE
,
5879 WINED3DRS_FOGDENSITY
,
5881 WINED3DRS_FOGSTART
,
5882 WINED3DRS_FOGTABLEMODE
,
5883 WINED3DRS_FOGVERTEXMODE
,
5884 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
5885 WINED3DRS_LIGHTING
,
5886 WINED3DRS_LOCALVIEWER
,
5887 WINED3DRS_MULTISAMPLEANTIALIAS
,
5888 WINED3DRS_MULTISAMPLEMASK
,
5889 WINED3DRS_NORMALIZENORMALS
,
5890 WINED3DRS_PATCHEDGESTYLE
,
5891 WINED3DRS_POINTSCALE_A
,
5892 WINED3DRS_POINTSCALE_B
,
5893 WINED3DRS_POINTSCALE_C
,
5894 WINED3DRS_POINTSCALEENABLE
,
5895 WINED3DRS_POINTSIZE
,
5896 WINED3DRS_POINTSIZE_MAX
,
5897 WINED3DRS_POINTSIZE_MIN
,
5898 WINED3DRS_POINTSPRITEENABLE
,
5899 WINED3DRS_RANGEFOGENABLE
,
5900 WINED3DRS_SPECULARMATERIALSOURCE
,
5901 WINED3DRS_TWEENFACTOR
,
5902 WINED3DRS_VERTEXBLEND
5905 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
5906 WINED3DTSS_TEXCOORDINDEX
,
5907 WINED3DTSS_TEXTURETRANSFORMFLAGS
5910 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
5911 WINED3DSAMP_DMAPOFFSET
5914 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
5915 DWORD rep
= StateTable
[state
].representative
;
5919 WineD3DContext
*context
;
5922 for(i
= 0; i
< This
->numContexts
; i
++) {
5923 context
= This
->contexts
[i
];
5924 if(isStateDirty(context
, rep
)) continue;
5926 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
5929 context
->isStateDirty
[idx
] |= (1 << shift
);