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 * Utility functions follow
153 **********************************************************/
154 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
155 static void setup_light(IWineD3DDevice
*iface
, LONG Index
, PLIGHTINFOEL
*lightInfo
) {
158 float colRGBA
[] = {0.0, 0.0, 0.0, 0.0};
159 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
161 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
162 glMatrixMode(GL_MODELVIEW
);
164 glLoadMatrixf((float *)&This
->stateBlock
->transforms
[WINED3DTS_VIEW
].u
.m
[0][0]);
167 colRGBA
[0] = lightInfo
->OriginalParms
.Diffuse
.r
;
168 colRGBA
[1] = lightInfo
->OriginalParms
.Diffuse
.g
;
169 colRGBA
[2] = lightInfo
->OriginalParms
.Diffuse
.b
;
170 colRGBA
[3] = lightInfo
->OriginalParms
.Diffuse
.a
;
171 glLightfv(GL_LIGHT0
+Index
, GL_DIFFUSE
, colRGBA
);
172 checkGLcall("glLightfv");
175 colRGBA
[0] = lightInfo
->OriginalParms
.Specular
.r
;
176 colRGBA
[1] = lightInfo
->OriginalParms
.Specular
.g
;
177 colRGBA
[2] = lightInfo
->OriginalParms
.Specular
.b
;
178 colRGBA
[3] = lightInfo
->OriginalParms
.Specular
.a
;
179 glLightfv(GL_LIGHT0
+Index
, GL_SPECULAR
, colRGBA
);
180 checkGLcall("glLightfv");
183 colRGBA
[0] = lightInfo
->OriginalParms
.Ambient
.r
;
184 colRGBA
[1] = lightInfo
->OriginalParms
.Ambient
.g
;
185 colRGBA
[2] = lightInfo
->OriginalParms
.Ambient
.b
;
186 colRGBA
[3] = lightInfo
->OriginalParms
.Ambient
.a
;
187 glLightfv(GL_LIGHT0
+Index
, GL_AMBIENT
, colRGBA
);
188 checkGLcall("glLightfv");
190 /* Attenuation - Are these right? guessing... */
191 glLightf(GL_LIGHT0
+Index
, GL_CONSTANT_ATTENUATION
, lightInfo
->OriginalParms
.Attenuation0
);
192 checkGLcall("glLightf");
193 glLightf(GL_LIGHT0
+Index
, GL_LINEAR_ATTENUATION
, lightInfo
->OriginalParms
.Attenuation1
);
194 checkGLcall("glLightf");
196 if ((lightInfo
->OriginalParms
.Range
*lightInfo
->OriginalParms
.Range
) >= FLT_MIN
) {
197 quad_att
= 1.4/(lightInfo
->OriginalParms
.Range
*lightInfo
->OriginalParms
.Range
);
199 quad_att
= 0; /* 0 or MAX? (0 seems to be ok) */
202 if (quad_att
< lightInfo
->OriginalParms
.Attenuation2
) quad_att
= lightInfo
->OriginalParms
.Attenuation2
;
203 glLightf(GL_LIGHT0
+Index
, GL_QUADRATIC_ATTENUATION
, quad_att
);
204 checkGLcall("glLightf");
206 switch (lightInfo
->OriginalParms
.Type
) {
207 case WINED3DLIGHT_POINT
:
209 glLightfv(GL_LIGHT0
+Index
, GL_POSITION
, &lightInfo
->lightPosn
[0]);
210 checkGLcall("glLightfv");
211 glLightf(GL_LIGHT0
+ Index
, GL_SPOT_CUTOFF
, lightInfo
->cutoff
);
212 checkGLcall("glLightf");
216 case WINED3DLIGHT_SPOT
:
218 glLightfv(GL_LIGHT0
+Index
, GL_POSITION
, &lightInfo
->lightPosn
[0]);
219 checkGLcall("glLightfv");
221 glLightfv(GL_LIGHT0
+Index
, GL_SPOT_DIRECTION
, &lightInfo
->lightDirn
[0]);
222 checkGLcall("glLightfv");
223 glLightf(GL_LIGHT0
+ Index
, GL_SPOT_EXPONENT
, lightInfo
->exponent
);
224 checkGLcall("glLightf");
225 glLightf(GL_LIGHT0
+ Index
, GL_SPOT_CUTOFF
, lightInfo
->cutoff
);
226 checkGLcall("glLightf");
230 case WINED3DLIGHT_DIRECTIONAL
:
232 glLightfv(GL_LIGHT0
+Index
, GL_POSITION
, &lightInfo
->lightPosn
[0]); /* Note gl uses w position of 0 for direction! */
233 checkGLcall("glLightfv");
234 glLightf(GL_LIGHT0
+Index
, GL_SPOT_CUTOFF
, lightInfo
->cutoff
);
235 checkGLcall("glLightf");
236 glLightf(GL_LIGHT0
+Index
, GL_SPOT_EXPONENT
, 0.0f
);
237 checkGLcall("glLightf");
241 FIXME("Unrecognized light type %d\n", lightInfo
->OriginalParms
.Type
);
244 /* Restore the modelview matrix */
248 /**********************************************************
249 * GLSL helper functions follow
250 **********************************************************/
252 /** Detach the GLSL pixel or vertex shader object from the shader program */
253 static void detach_glsl_shader(IWineD3DDevice
*iface
, GLhandleARB shaderObj
, GLhandleARB programId
) {
255 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
257 if (shaderObj
!= 0 && programId
!= 0) {
258 TRACE_(d3d_shader
)("Detaching GLSL shader object %u from program %u\n", shaderObj
, programId
);
259 GL_EXTCALL(glDetachObjectARB(programId
, shaderObj
));
260 checkGLcall("glDetachObjectARB");
264 /** Delete a GLSL shader program */
265 static void delete_glsl_shader_program(IWineD3DDevice
*iface
, GLhandleARB obj
) {
267 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
270 TRACE_(d3d_shader
)("Deleting GLSL shader program %u\n", obj
);
271 GL_EXTCALL(glDeleteObjectARB(obj
));
272 checkGLcall("glDeleteObjectARB");
276 /** Delete the list of linked programs this shader is associated with.
277 * Also at this point, check to see if there are any objects left attached
278 * to each GLSL program. If not, delete the GLSL program object.
279 * This will be run when a device is released. */
280 static void delete_glsl_shader_list(IWineD3DDevice
* iface
) {
282 struct list
*ptr
= NULL
;
283 struct glsl_shader_prog_link
*curLink
= NULL
;
284 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
288 GLhandleARB objList
[2]; /* There should never be more than 2 objects attached
289 (one pixel shader and one vertex shader at most) */
291 ptr
= list_head( &This
->glsl_shader_progs
);
293 /* First, get the current item,
294 * save the link to the next pointer,
295 * detach and delete shader objects,
296 * then de-allocate the list item's memory */
297 curLink
= LIST_ENTRY( ptr
, struct glsl_shader_prog_link
, entry
);
298 ptr
= list_next( &This
->glsl_shader_progs
, ptr
);
300 /* See if this object is still attached to the program - it may have been detached already */
301 GL_EXTCALL(glGetAttachedObjectsARB(curLink
->programId
, 2, &numAttached
, objList
));
302 TRACE_(d3d_shader
)("%i GLSL objects are currently attached to program %u\n", numAttached
, curLink
->programId
);
303 for (i
= 0; i
< numAttached
; i
++) {
304 detach_glsl_shader(iface
, objList
[i
], curLink
->programId
);
307 delete_glsl_shader_program(iface
, curLink
->programId
);
309 /* Free the uniform locations */
310 HeapFree(GetProcessHeap(), 0, curLink
->vuniformF_locations
);
311 HeapFree(GetProcessHeap(), 0, curLink
->puniformF_locations
);
313 /* Free the memory for this list item */
314 HeapFree(GetProcessHeap(), 0, curLink
);
318 /**********************************************************
319 * IUnknown parts follows
320 **********************************************************/
322 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
324 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
326 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
327 if (IsEqualGUID(riid
, &IID_IUnknown
)
328 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
329 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
330 IUnknown_AddRef(iface
);
335 return E_NOINTERFACE
;
338 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
339 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
340 ULONG refCount
= InterlockedIncrement(&This
->ref
);
342 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
346 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
347 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
348 ULONG refCount
= InterlockedDecrement(&This
->ref
);
350 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
354 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
357 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
359 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
361 /* TODO: Clean up all the surfaces and textures! */
362 /* NOTE: You must release the parent if the object was created via a callback
363 ** ***************************/
365 /* Delete any GLSL shader programs that may exist */
366 if (This
->vs_selected_mode
== SHADER_GLSL
||
367 This
->ps_selected_mode
== SHADER_GLSL
)
368 delete_glsl_shader_list(iface
);
370 /* Release the update stateblock */
371 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
372 if(This
->updateStateBlock
!= This
->stateBlock
)
373 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
375 This
->updateStateBlock
= NULL
;
376 { /* because were not doing proper internal refcounts releasing the primary state block
377 causes recursion with the extra checks in ResourceReleased, to avoid this we have
378 to set this->stateBlock = NULL; first */
379 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
380 This
->stateBlock
= NULL
;
382 /* Release the stateblock */
383 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
384 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
388 if (This
->resources
!= NULL
) {
389 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
390 dumpResources(This
->resources
);
394 IWineD3D_Release(This
->wineD3D
);
395 This
->wineD3D
= NULL
;
396 HeapFree(GetProcessHeap(), 0, This
);
397 TRACE("Freed device %p\n", This
);
403 /**********************************************************
404 * IWineD3DDevice implementation follows
405 **********************************************************/
406 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
407 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
408 *pParent
= This
->parent
;
409 IUnknown_AddRef(This
->parent
);
413 static void CreateVBO(IWineD3DVertexBufferImpl
*object
) {
414 IWineD3DDeviceImpl
*This
= object
->resource
.wineD3DDevice
; /* Needed for GL_EXTCALL */
415 GLenum error
, glUsage
;
416 DWORD vboUsage
= object
->resource
.usage
;
417 if(object
->Flags
& VBFLAG_VBOCREATEFAIL
) {
418 WARN("Creating a vbo failed once, not trying again\n");
422 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object
, debug_d3dusage(vboUsage
));
425 /* Make sure that the gl error is cleared. Do not use checkGLcall
426 * here because checkGLcall just prints a fixme and continues. However,
427 * if an error during VBO creation occurs we can fall back to non-vbo operation
428 * with full functionality(but performance loss)
430 while(glGetError() != GL_NO_ERROR
);
432 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
433 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
434 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
435 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
436 * to check if the rhw and color values are in the correct format.
439 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
440 error
= glGetError();
441 if(object
->vbo
== 0 || error
!= GL_NO_ERROR
) {
442 WARN("Failed to create a VBO with error %d\n", error
);
446 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, object
->vbo
));
447 error
= glGetError();
448 if(error
!= GL_NO_ERROR
) {
449 WARN("Failed to bind the VBO, error %d\n", error
);
453 /* Don't use static, because dx apps tend to update the buffer
454 * quite often even if they specify 0 usage
456 switch(vboUsage
& (D3DUSAGE_WRITEONLY
| D3DUSAGE_DYNAMIC
) ) {
457 case D3DUSAGE_WRITEONLY
| D3DUSAGE_DYNAMIC
:
458 TRACE("Gl usage = GL_STREAM_DRAW\n");
459 glUsage
= GL_STREAM_DRAW_ARB
;
461 case D3DUSAGE_WRITEONLY
:
462 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
463 glUsage
= GL_DYNAMIC_DRAW_ARB
;
465 case D3DUSAGE_DYNAMIC
:
466 TRACE("Gl usage = GL_STREAM_COPY\n");
467 glUsage
= GL_STREAM_COPY_ARB
;
470 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
471 glUsage
= GL_DYNAMIC_COPY_ARB
;
475 /* Reserve memory for the buffer. The amount of data won't change
476 * so we are safe with calling glBufferData once with a NULL ptr and
477 * calling glBufferSubData on updates
479 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
480 error
= glGetError();
481 if(error
!= GL_NO_ERROR
) {
482 WARN("glBufferDataARB failed with error %d\n", error
);
490 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
491 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
492 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
494 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
499 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
500 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
502 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
503 IWineD3DVertexBufferImpl
*object
;
504 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
505 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
507 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
509 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
510 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
512 if(Size
== 0) return WINED3DERR_INVALIDCALL
;
514 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
515 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->resource
.size
);
519 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
520 * drawStridedFast (half-life 2).
522 * Basically converting the vertices in the buffer is quite expensive, and observations
523 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
524 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
526 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
527 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
528 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
529 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
531 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
532 * more. In this call we can convert dx7 buffers too.
534 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
535 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
) && Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) &&
536 (dxVersion
> 7 || !conv
) ) {
539 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
540 if(dxVersion
== 7 && object
->vbo
) {
541 HeapFree(GetProcessHeap(), 0, object
->resource
.allocatedMemory
);
542 object
->resource
.allocatedMemory
= NULL
;
549 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
550 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
551 HANDLE
*sharedHandle
, IUnknown
*parent
) {
552 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
553 IWineD3DIndexBufferImpl
*object
;
554 TRACE("(%p) Creating index buffer\n", This
);
556 /* Allocate the storage for the device */
557 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
560 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
561 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,object
->resource
.size
);
564 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
565 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
566 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
571 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
573 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
574 IWineD3DStateBlockImpl
*object
;
578 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
579 object
->blockType
= Type
;
581 /* Special case - Used during initialization to produce a placeholder stateblock
582 so other functions called can update a state block */
583 if (Type
== WINED3DSBT_INIT
) {
584 /* Don't bother increasing the reference count otherwise a device will never
585 be freed due to circular dependencies */
589 temp_result
= allocate_shader_constants(object
);
590 if (WINED3D_OK
!= temp_result
)
593 /* Otherwise, might as well set the whole state block to the appropriate values */
594 if (This
->stateBlock
!= NULL
)
595 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
597 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
599 /* Reset the ref and type after kludging it */
600 object
->wineD3DDevice
= This
;
602 object
->blockType
= Type
;
604 TRACE("Updating changed flags appropriate for type %d\n", Type
);
606 if (Type
== WINED3DSBT_ALL
) {
608 TRACE("ALL => Pretend everything has changed\n");
609 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
611 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
613 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
614 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
616 object
->changed
.pixelShader
= TRUE
;
618 /* Pixel Shader Constants */
619 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
)
620 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
621 for (i
= 0; i
< MAX_CONST_B
; ++i
)
622 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
623 for (i
= 0; i
< MAX_CONST_I
; ++i
)
624 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
626 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
627 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
629 for (j
= 0; j
< GL_LIMITS(texture_stages
); j
++) {
630 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
631 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
634 for (j
= 0 ; j
< 16; j
++) {
635 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
637 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
641 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
643 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
644 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
646 object
->changed
.vertexShader
= TRUE
;
648 /* Vertex Shader Constants */
649 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
)
650 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
651 for (i
= 0; i
< MAX_CONST_B
; ++i
)
652 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
653 for (i
= 0; i
< MAX_CONST_I
; ++i
)
654 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
656 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
657 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
659 for (j
= 0; j
< GL_LIMITS(texture_stages
); j
++) {
660 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
661 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
664 for (j
= 0 ; j
< 16; j
++){
665 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
666 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
670 /* Duplicate light chain */
672 PLIGHTINFOEL
*src
= NULL
;
673 PLIGHTINFOEL
*dst
= NULL
;
674 PLIGHTINFOEL
*newEl
= NULL
;
675 src
= This
->stateBlock
->lights
;
676 object
->lights
= NULL
;
680 newEl
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PLIGHTINFOEL
));
681 if (newEl
== NULL
) return WINED3DERR_OUTOFVIDEOMEMORY
;
682 memcpy(newEl
, src
, sizeof(PLIGHTINFOEL
));
684 newEl
->changed
= TRUE
;
685 newEl
->enabledChanged
= TRUE
;
687 object
->lights
= newEl
;
698 FIXME("Unrecognized state block type %d\n", Type
);
701 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
706 /* ************************************
708 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
711 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
713 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.
715 ******************************** */
717 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
) {
718 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
719 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
720 unsigned int pow2Width
, pow2Height
;
721 unsigned int Size
= 1;
722 const PixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
);
723 TRACE("(%p) Create surface\n",This
);
725 /** FIXME: Check ranges on the inputs are valid
728 * [in] Quality level. The valid range is between zero and one less than the level
729 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
730 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
731 * values of paired render targets, depth stencil surfaces, and the MultiSample type
733 *******************************/
738 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
740 * If this flag is set, the contents of the depth stencil buffer will be
741 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
742 * with a different depth surface.
744 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
745 ***************************/
747 if(MultisampleQuality
< 0) {
748 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
749 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
752 if(MultisampleQuality
> 0) {
753 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
754 MultisampleQuality
=0;
757 /** FIXME: Check that the format is supported
759 *******************************/
761 /* Non-power2 support */
762 if (wined3d_settings
.nonpower2_mode
== NP2_NATIVE
) {
766 /* Find the nearest pow2 match */
767 pow2Width
= pow2Height
= 1;
768 while (pow2Width
< Width
) pow2Width
<<= 1;
769 while (pow2Height
< Height
) pow2Height
<<= 1;
772 if (pow2Width
> Width
|| pow2Height
> Height
) {
773 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
774 if (Format
== WINED3DFMT_DXT1
|| Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
775 || Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
776 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
777 This
, Width
, Height
);
778 return WINED3DERR_NOTAVAILABLE
;
782 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
783 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
785 *********************************/
786 if (WINED3DFMT_UNKNOWN
== Format
) {
788 } else if (Format
== WINED3DFMT_DXT1
) {
789 /* DXT1 is half byte per pixel */
790 Size
= ((max(pow2Width
,4) * tableEntry
->bpp
) * max(pow2Height
,4)) >> 1;
792 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
793 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
794 Size
= ((max(pow2Width
,4) * tableEntry
->bpp
) * max(pow2Height
,4));
796 /* The pitch is a multiple of 4 bytes */
797 Size
= ((pow2Width
* tableEntry
->bpp
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
801 /** Create and initialise the surface resource **/
802 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
803 /* "Standalone" surface */
804 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
806 object
->currentDesc
.Width
= Width
;
807 object
->currentDesc
.Height
= Height
;
808 object
->currentDesc
.MultiSampleType
= MultiSample
;
809 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
811 /* Setup some glformat defaults */
812 object
->glDescription
.glFormat
= tableEntry
->glFormat
;
813 object
->glDescription
.glFormatInternal
= tableEntry
->glInternal
;
814 object
->glDescription
.glType
= tableEntry
->glType
;
816 object
->glDescription
.textureName
= 0;
817 object
->glDescription
.level
= Level
;
818 object
->glDescription
.target
= GL_TEXTURE_2D
;
821 object
->pow2Width
= pow2Width
;
822 object
->pow2Height
= pow2Height
;
825 object
->Flags
= 0; /* We start without flags set */
826 object
->Flags
|= (pow2Width
!= Width
|| pow2Height
!= Height
) ? SFLAG_NONPOW2
: 0;
827 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
828 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
829 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
832 if (WINED3DFMT_UNKNOWN
!= Format
) {
833 object
->bytesPerPixel
= tableEntry
->bpp
;
834 object
->pow2Size
= ((pow2Width
* object
->bytesPerPixel
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
835 object
->pow2Size
*= pow2Height
;
837 object
->bytesPerPixel
= 0;
838 object
->pow2Size
= 0;
841 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
843 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
845 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
846 * this function is too deep to need to care about things like this.
847 * Levels need to be checked too, and possibly Type since they all affect what can be done.
848 * ****************************************/
850 case WINED3DPOOL_SCRATCH
:
852 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
853 "which are mutually exclusive, setting lockable to TRUE\n");
856 case WINED3DPOOL_SYSTEMMEM
:
857 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
858 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
859 case WINED3DPOOL_MANAGED
:
860 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
861 "Usage of DYNAMIC which are mutually exclusive, not doing "
862 "anything just telling you.\n");
864 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
865 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
866 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
867 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
870 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
874 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
875 FIXME("Trying to create a render target that isn't in the default pool\n");
878 /* mark the texture as dirty so that it gets loaded first time around*/
879 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
880 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
881 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
882 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
884 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
885 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
886 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
888 /* Look at the implementation and set the correct Vtable */
891 /* Nothing to do, it's set already */
895 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
899 /* To be sure to catch this */
900 ERR("Unknown requested surface implementation %d!\n", Impl
);
901 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
902 return WINED3DERR_INVALIDCALL
;
905 /* Call the private setup routine */
906 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
910 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
911 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
912 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
913 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
915 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
916 IWineD3DTextureImpl
*object
;
921 unsigned int pow2Width
;
922 unsigned int pow2Height
;
925 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
926 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
927 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
929 /* TODO: It should only be possible to create textures for formats
930 that are reported as supported */
931 if (WINED3DFMT_UNKNOWN
>= Format
) {
932 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
933 return WINED3DERR_INVALIDCALL
;
936 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
937 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
938 object
->width
= Width
;
939 object
->height
= Height
;
941 /** Non-power2 support **/
942 if (wined3d_settings
.nonpower2_mode
== NP2_NATIVE
) {
946 /* Find the nearest pow2 match */
947 pow2Width
= pow2Height
= 1;
948 while (pow2Width
< Width
) pow2Width
<<= 1;
949 while (pow2Height
< Height
) pow2Height
<<= 1;
952 /** FIXME: add support for real non-power-two if it's provided by the video card **/
953 /* Precalculated scaling for 'faked' non power of two texture coords */
954 object
->pow2scalingFactorX
= (((float)Width
) / ((float)pow2Width
));
955 object
->pow2scalingFactorY
= (((float)Height
) / ((float)pow2Height
));
956 TRACE(" xf(%f) yf(%f)\n", object
->pow2scalingFactorX
, object
->pow2scalingFactorY
);
958 /* Calculate levels for mip mapping */
960 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
961 object
->baseTexture
.levels
++;
964 while (tmpW
> 1 || tmpH
> 1) {
965 tmpW
= max(1, tmpW
>> 1);
966 tmpH
= max(1, tmpH
>> 1);
967 object
->baseTexture
.levels
++;
969 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
972 /* Generate all the surfaces */
975 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
977 /* use the callback to create the texture surface */
978 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, &object
->surfaces
[i
],NULL
);
979 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
980 FIXME("Failed to create surface %p\n", object
);
982 object
->surfaces
[i
] = NULL
;
983 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
989 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
990 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
991 /* calculate the next mipmap level */
992 tmpW
= max(1, tmpW
>> 1);
993 tmpH
= max(1, tmpH
>> 1);
996 TRACE("(%p) : Created texture %p\n", This
, object
);
1000 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
1001 UINT Width
, UINT Height
, UINT Depth
,
1002 UINT Levels
, DWORD Usage
,
1003 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1004 IWineD3DVolumeTexture
**ppVolumeTexture
,
1005 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1006 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
1008 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1009 IWineD3DVolumeTextureImpl
*object
;
1015 /* TODO: It should only be possible to create textures for formats
1016 that are reported as supported */
1017 if (WINED3DFMT_UNKNOWN
>= Format
) {
1018 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1019 return WINED3DERR_INVALIDCALL
;
1022 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
1023 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1025 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1026 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1028 object
->width
= Width
;
1029 object
->height
= Height
;
1030 object
->depth
= Depth
;
1032 /* Calculate levels for mip mapping */
1034 object
->baseTexture
.levels
++;
1038 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
1039 tmpW
= max(1, tmpW
>> 1);
1040 tmpH
= max(1, tmpH
>> 1);
1041 tmpD
= max(1, tmpD
>> 1);
1042 object
->baseTexture
.levels
++;
1044 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1047 /* Generate all the surfaces */
1052 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1054 /* Create the volume */
1055 D3DCB_CreateVolume(This
->parent
, parent
, Width
, Height
, Depth
, Format
, Pool
, Usage
,
1056 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
1058 /* Set its container to this object */
1059 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1061 /* calcualte the next mipmap level */
1062 tmpW
= max(1, tmpW
>> 1);
1063 tmpH
= max(1, tmpH
>> 1);
1064 tmpD
= max(1, tmpD
>> 1);
1067 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1068 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1072 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1073 UINT Width
, UINT Height
, UINT Depth
,
1075 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1076 IWineD3DVolume
** ppVolume
,
1077 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
1079 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1080 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1081 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
);
1083 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
1085 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1086 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1088 object
->currentDesc
.Width
= Width
;
1089 object
->currentDesc
.Height
= Height
;
1090 object
->currentDesc
.Depth
= Depth
;
1091 object
->bytesPerPixel
= formatDesc
->bpp
;
1093 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1094 object
->lockable
= TRUE
;
1095 object
->locked
= FALSE
;
1096 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1097 object
->dirty
= TRUE
;
1099 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
1102 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
1103 UINT Levels
, DWORD Usage
,
1104 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1105 IWineD3DCubeTexture
**ppCubeTexture
,
1106 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1107 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1109 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1110 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1114 unsigned int pow2EdgeLength
= EdgeLength
;
1116 /* TODO: It should only be possible to create textures for formats
1117 that are reported as supported */
1118 if (WINED3DFMT_UNKNOWN
>= Format
) {
1119 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1120 return WINED3DERR_INVALIDCALL
;
1123 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1124 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1126 TRACE("(%p) Create Cube Texture\n", This
);
1128 /** Non-power2 support **/
1130 /* Find the nearest pow2 match */
1132 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1134 object
->edgeLength
= EdgeLength
;
1135 /* TODO: support for native non-power 2 */
1136 /* Precalculated scaling for 'faked' non power of two texture coords */
1137 object
->pow2scalingFactor
= ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1139 /* Calculate levels for mip mapping */
1141 object
->baseTexture
.levels
++;
1144 tmpW
= max(1, tmpW
>> 1);
1145 object
->baseTexture
.levels
++;
1147 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1150 /* Generate all the surfaces */
1152 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1154 /* Create the 6 faces */
1155 for (j
= 0; j
< 6; j
++) {
1157 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1158 i
/* Level */, &object
->surfaces
[j
][i
],pSharedHandle
);
1160 if(hr
!= WINED3D_OK
) {
1164 for (l
= 0; l
< j
; l
++) {
1165 IWineD3DSurface_Release(object
->surfaces
[j
][i
]);
1167 for (k
= 0; k
< i
; k
++) {
1168 for (l
= 0; l
< 6; l
++) {
1169 IWineD3DSurface_Release(object
->surfaces
[l
][j
]);
1173 FIXME("(%p) Failed to create surface\n",object
);
1174 HeapFree(GetProcessHeap(),0,object
);
1175 *ppCubeTexture
= NULL
;
1178 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1179 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1181 tmpW
= max(1, tmpW
>> 1);
1184 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1185 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1189 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1190 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1191 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1193 if (NULL
== ppQuery
) {
1194 /* Just a check to see if we support this type of query */
1195 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1197 case WINED3DQUERYTYPE_OCCLUSION
:
1198 TRACE("(%p) occlusion query\n", This
);
1199 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1202 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1204 case WINED3DQUERYTYPE_VCACHE
:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1206 case WINED3DQUERYTYPE_VERTEXSTATS
:
1207 case WINED3DQUERYTYPE_EVENT
:
1208 case WINED3DQUERYTYPE_TIMESTAMP
:
1209 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1210 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1211 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1212 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1213 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1214 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1215 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1216 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1218 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1223 D3DCREATEOBJECTINSTANCE(object
, Query
)
1224 object
->type
= Type
;
1225 /* allocated the 'extended' data based on the type of query requested */
1227 case WINED3DQUERYTYPE_OCCLUSION
:
1228 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1229 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1230 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1231 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1234 case WINED3DQUERYTYPE_VCACHE
:
1235 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1236 case WINED3DQUERYTYPE_VERTEXSTATS
:
1237 case WINED3DQUERYTYPE_EVENT
:
1238 case WINED3DQUERYTYPE_TIMESTAMP
:
1239 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1240 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1241 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1242 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1243 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1244 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1245 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1246 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1248 object
->extendedData
= 0;
1249 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1251 TRACE("(%p) : Created Query %p\n", This
, object
);
1255 /*****************************************************************************
1256 * IWineD3DDeviceImpl_SetupFullscreenWindow
1258 * Helper function that modifies a HWND's Style and ExStyle for proper
1262 * iface: Pointer to the IWineD3DDevice interface
1263 * window: Window to setup
1265 *****************************************************************************/
1266 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1267 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1269 LONG style
, exStyle
;
1270 /* Don't do anything if an original style is stored.
1271 * That shouldn't happen
1273 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1274 if (This
->style
&& This
->exStyle
) {
1275 ERR("(%p): Want to change the window parameters of HWND %p, but "
1276 "another style is stored for restoration afterwards\n", This
, window
);
1279 /* Get the parameters and save them */
1280 style
= GetWindowLongW(window
, GWL_STYLE
);
1281 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1282 This
->style
= style
;
1283 This
->exStyle
= exStyle
;
1285 /* Filter out window decorations */
1286 style
&= ~WS_CAPTION
;
1287 style
&= ~WS_THICKFRAME
;
1288 exStyle
&= ~WS_EX_WINDOWEDGE
;
1289 exStyle
&= ~WS_EX_CLIENTEDGE
;
1291 /* Make sure the window is managed, otherwise we won't get keyboard input */
1292 style
|= WS_POPUP
| WS_SYSMENU
;
1294 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1295 This
->style
, This
->exStyle
, style
, exStyle
);
1297 SetWindowLongW(window
, GWL_STYLE
, style
);
1298 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1300 /* Inform the window about the update. */
1301 SetWindowPos(window
, HWND_TOP
, 0, 0,
1302 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1305 /*****************************************************************************
1306 * IWineD3DDeviceImpl_RestoreWindow
1308 * Helper function that restores a windows' properties when taking it out
1309 * of fullscreen mode
1312 * iface: Pointer to the IWineD3DDevice interface
1313 * window: Window to setup
1315 *****************************************************************************/
1316 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1317 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1319 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1320 * switch, do nothing
1322 if (!This
->style
&& !This
->exStyle
) return;
1324 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1325 This
, window
, This
->style
, This
->exStyle
);
1327 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1328 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1330 /* Delete the old values */
1334 /* Inform the window about the update */
1335 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1336 0, 0, 0, 0, /* Pos, Size, ignored */
1337 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1340 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1341 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1343 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1344 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1345 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1348 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1350 XVisualInfo
template;
1351 GLXContext oldContext
;
1352 Drawable oldDrawable
;
1353 HRESULT hr
= WINED3D_OK
;
1355 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1357 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1358 * does a device hold a reference to a swap chain giving them a lifetime of the device
1359 * or does the swap chain notify the device of its destruction.
1360 *******************************/
1362 /* Check the params */
1363 if(*pPresentationParameters
->BackBufferCount
> D3DPRESENT_BACK_BUFFER_MAX
) {
1364 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters
->BackBufferCount
);
1365 return WINED3DERR_INVALIDCALL
;
1366 } else if (*pPresentationParameters
->BackBufferCount
> 1) {
1367 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1370 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1372 /*********************
1373 * Lookup the window Handle and the relating X window handle
1374 ********************/
1376 /* Setup hwnd we are using, plus which display this equates to */
1377 object
->win_handle
= *(pPresentationParameters
->hDeviceWindow
);
1378 if (!object
->win_handle
) {
1379 object
->win_handle
= This
->createParms
.hFocusWindow
;
1382 object
->win_handle
= GetAncestor(object
->win_handle
, GA_ROOT
);
1383 if ( !( object
->win
= (Window
)GetPropA(object
->win_handle
, "__wine_x11_whole_window") ) ) {
1384 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object
->win_handle
);
1385 return WINED3DERR_NOTAVAILABLE
;
1387 hDc
= GetDC(object
->win_handle
);
1388 object
->display
= get_display(hDc
);
1389 ReleaseDC(object
->win_handle
, hDc
);
1390 TRACE("Using a display of %p %p\n", object
->display
, hDc
);
1392 if (NULL
== object
->display
|| NULL
== hDc
) {
1393 WARN("Failed to get a display and HDc for Window %p\n", object
->win_handle
);
1394 return WINED3DERR_NOTAVAILABLE
;
1397 if (object
->win
== 0) {
1398 WARN("Failed to get a valid XVisuial ID for the window %p\n", object
->win_handle
);
1399 return WINED3DERR_NOTAVAILABLE
;
1402 object
->orig_width
= GetSystemMetrics(SM_CXSCREEN
);
1403 object
->orig_height
= GetSystemMetrics(SM_CYSCREEN
);
1406 * Create an opengl context for the display visual
1407 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1408 * use different properties after that point in time. FIXME: How to handle when requested format
1409 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1410 * it chooses is identical to the one already being used!
1411 **********************************/
1413 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1416 /* Create a new context for this swapchain */
1417 template.visualid
= (VisualID
)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1418 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1419 (or the best possible if none is requested) */
1420 TRACE("Found x visual ID : %ld\n", template.visualid
);
1422 object
->visInfo
= XGetVisualInfo(object
->display
, VisualIDMask
, &template, &num
);
1423 if (NULL
== object
->visInfo
) {
1424 ERR("cannot really get XVisual\n");
1426 return WINED3DERR_NOTAVAILABLE
;
1429 /* Write out some debug info about the visual/s */
1430 TRACE("Using x visual ID : %ld\n", template.visualid
);
1431 TRACE(" visual info: %p\n", object
->visInfo
);
1432 TRACE(" num items : %d\n", num
);
1433 for (n
= 0;n
< num
; n
++) {
1434 TRACE("=====item=====: %d\n", n
+ 1);
1435 TRACE(" visualid : %ld\n", object
->visInfo
[n
].visualid
);
1436 TRACE(" screen : %d\n", object
->visInfo
[n
].screen
);
1437 TRACE(" depth : %u\n", object
->visInfo
[n
].depth
);
1438 TRACE(" class : %d\n", object
->visInfo
[n
].class);
1439 TRACE(" red_mask : %ld\n", object
->visInfo
[n
].red_mask
);
1440 TRACE(" green_mask : %ld\n", object
->visInfo
[n
].green_mask
);
1441 TRACE(" blue_mask : %ld\n", object
->visInfo
[n
].blue_mask
);
1442 TRACE(" colormap_size : %d\n", object
->visInfo
[n
].colormap_size
);
1443 TRACE(" bits_per_rgb : %d\n", object
->visInfo
[n
].bits_per_rgb
);
1444 /* log some extra glx info */
1445 glXGetConfig(object
->display
, object
->visInfo
, GLX_AUX_BUFFERS
, &value
);
1446 TRACE(" gl_aux_buffers : %d\n", value
);
1447 glXGetConfig(object
->display
, object
->visInfo
, GLX_BUFFER_SIZE
,&value
);
1448 TRACE(" gl_buffer_size : %d\n", value
);
1449 glXGetConfig(object
->display
, object
->visInfo
, GLX_RED_SIZE
, &value
);
1450 TRACE(" gl_red_size : %d\n", value
);
1451 glXGetConfig(object
->display
, object
->visInfo
, GLX_GREEN_SIZE
, &value
);
1452 TRACE(" gl_green_size : %d\n", value
);
1453 glXGetConfig(object
->display
, object
->visInfo
, GLX_BLUE_SIZE
, &value
);
1454 TRACE(" gl_blue_size : %d\n", value
);
1455 glXGetConfig(object
->display
, object
->visInfo
, GLX_ALPHA_SIZE
, &value
);
1456 TRACE(" gl_alpha_size : %d\n", value
);
1457 glXGetConfig(object
->display
, object
->visInfo
, GLX_DEPTH_SIZE
,&value
);
1458 TRACE(" gl_depth_size : %d\n", value
);
1459 glXGetConfig(object
->display
, object
->visInfo
, GLX_STENCIL_SIZE
, &value
);
1460 TRACE(" gl_stencil_size : %d\n", value
);
1462 /* Now choose a similar visual ID*/
1464 #ifdef USE_CONTEXT_MANAGER
1466 /** TODO: use a context mamager **/
1470 IWineD3DSwapChain
*implSwapChain
;
1471 if (WINED3D_OK
!= IWineD3DDevice_GetSwapChain(iface
, 0, &implSwapChain
)) {
1472 /* The first time around we create the context that is shared with all other swapchains and render targets */
1473 object
->glCtx
= glXCreateContext(object
->display
, object
->visInfo
, NULL
, GL_TRUE
);
1474 TRACE("Creating implicit context for vis %p, hwnd %p\n", object
->display
, object
->visInfo
);
1477 TRACE("Creating context for vis %p, hwnd %p\n", object
->display
, object
->visInfo
);
1478 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1479 /* and create a new context with the implicit swapchains context as the shared context */
1480 object
->glCtx
= glXCreateContext(object
->display
, object
->visInfo
, ((IWineD3DSwapChainImpl
*)implSwapChain
)->glCtx
, GL_TRUE
);
1481 IWineD3DSwapChain_Release(implSwapChain
);
1486 XFree(object
->visInfo
);
1487 object
->visInfo
= NULL
;
1491 if (!object
->glCtx
) {
1492 ERR("Failed to create GLX context\n");
1493 return WINED3DERR_NOTAVAILABLE
;
1495 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1496 object
->win_handle
, object
->glCtx
, object
->win
, object
->visInfo
);
1499 /*********************
1500 * Windowed / Fullscreen
1501 *******************/
1504 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1505 * so we should really check to see if there is a fullscreen swapchain already
1506 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1507 **************************************/
1509 if (!*(pPresentationParameters
->Windowed
)) {
1516 /* Get info on the current display setup */
1518 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1521 /* Change the display settings */
1522 memset(&devmode
, 0, sizeof(DEVMODEW
));
1523 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1524 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1525 devmode
.dmPelsWidth
= *(pPresentationParameters
->BackBufferWidth
);
1526 devmode
.dmPelsHeight
= *(pPresentationParameters
->BackBufferHeight
);
1527 MultiByteToWideChar(CP_ACP
, 0, "Gamers CG", -1, devmode
.dmDeviceName
, CCHDEVICENAME
);
1528 ChangeDisplaySettingsExW(devmode
.dmDeviceName
, &devmode
, object
->win_handle
, CDS_FULLSCREEN
, NULL
);
1530 /* For GetDisplayMode */
1531 This
->ddraw_width
= devmode
.dmPelsWidth
;
1532 This
->ddraw_height
= devmode
.dmPelsHeight
;
1533 This
->ddraw_format
= *(pPresentationParameters
->BackBufferFormat
);
1535 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
);
1537 /* And finally clip mouse to our screen */
1538 SetRect(&clip_rc
, 0, 0, devmode
.dmPelsWidth
, devmode
.dmPelsHeight
);
1539 ClipCursor(&clip_rc
);
1543 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1544 * then the corresponding dimension of the client area of the hDeviceWindow
1545 * (or the focus window, if hDeviceWindow is NULL) is taken.
1546 **********************/
1548 if (*(pPresentationParameters
->Windowed
) &&
1549 ((*(pPresentationParameters
->BackBufferWidth
) == 0) ||
1550 (*(pPresentationParameters
->BackBufferHeight
) == 0))) {
1553 GetClientRect(object
->win_handle
, &Rect
);
1555 if (*(pPresentationParameters
->BackBufferWidth
) == 0) {
1556 *(pPresentationParameters
->BackBufferWidth
) = Rect
.right
;
1557 TRACE("Updating width to %d\n", *(pPresentationParameters
->BackBufferWidth
));
1559 if (*(pPresentationParameters
->BackBufferHeight
) == 0) {
1560 *(pPresentationParameters
->BackBufferHeight
) = Rect
.bottom
;
1561 TRACE("Updating height to %d\n", *(pPresentationParameters
->BackBufferHeight
));
1565 /*********************
1566 * finish off parameter initialization
1567 *******************/
1569 /* Put the correct figures in the presentation parameters */
1570 TRACE("Copying across presentation parameters\n");
1571 object
->presentParms
.BackBufferWidth
= *(pPresentationParameters
->BackBufferWidth
);
1572 object
->presentParms
.BackBufferHeight
= *(pPresentationParameters
->BackBufferHeight
);
1573 object
->presentParms
.BackBufferFormat
= *(pPresentationParameters
->BackBufferFormat
);
1574 object
->presentParms
.BackBufferCount
= *(pPresentationParameters
->BackBufferCount
);
1575 object
->presentParms
.MultiSampleType
= *(pPresentationParameters
->MultiSampleType
);
1576 object
->presentParms
.MultiSampleQuality
= NULL
== pPresentationParameters
->MultiSampleQuality
? 0 : *(pPresentationParameters
->MultiSampleQuality
);
1577 object
->presentParms
.SwapEffect
= *(pPresentationParameters
->SwapEffect
);
1578 object
->presentParms
.hDeviceWindow
= *(pPresentationParameters
->hDeviceWindow
);
1579 object
->presentParms
.Windowed
= *(pPresentationParameters
->Windowed
);
1580 object
->presentParms
.EnableAutoDepthStencil
= *(pPresentationParameters
->EnableAutoDepthStencil
);
1581 object
->presentParms
.AutoDepthStencilFormat
= *(pPresentationParameters
->AutoDepthStencilFormat
);
1582 object
->presentParms
.Flags
= *(pPresentationParameters
->Flags
);
1583 object
->presentParms
.FullScreen_RefreshRateInHz
= *(pPresentationParameters
->FullScreen_RefreshRateInHz
);
1584 object
->presentParms
.PresentationInterval
= *(pPresentationParameters
->PresentationInterval
);
1587 /*********************
1588 * Create the back, front and stencil buffers
1589 *******************/
1591 TRACE("calling rendertarget CB\n");
1592 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1594 object
->presentParms
.BackBufferWidth
,
1595 object
->presentParms
.BackBufferHeight
,
1596 object
->presentParms
.BackBufferFormat
,
1597 object
->presentParms
.MultiSampleType
,
1598 object
->presentParms
.MultiSampleQuality
,
1599 TRUE
/* Lockable */,
1600 &object
->frontBuffer
,
1601 NULL
/* pShared (always null)*/);
1602 if (object
->frontBuffer
!= NULL
)
1603 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1605 if(object
->presentParms
.BackBufferCount
> 0) {
1608 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1609 if(!object
->backBuffer
) {
1610 ERR("Out of memory\n");
1612 if (object
->frontBuffer
) {
1613 IUnknown
*bufferParent
;
1614 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1615 IUnknown_Release(bufferParent
); /* once for the get parent */
1616 if (IUnknown_Release(bufferParent
) > 0) {
1617 FIXME("(%p) Something's still holding the front buffer\n",This
);
1620 HeapFree(GetProcessHeap(), 0, object
);
1621 return E_OUTOFMEMORY
;
1624 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1625 TRACE("calling rendertarget CB\n");
1626 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1628 object
->presentParms
.BackBufferWidth
,
1629 object
->presentParms
.BackBufferHeight
,
1630 object
->presentParms
.BackBufferFormat
,
1631 object
->presentParms
.MultiSampleType
,
1632 object
->presentParms
.MultiSampleQuality
,
1633 TRUE
/* Lockable */,
1634 &object
->backBuffer
[i
],
1635 NULL
/* pShared (always null)*/);
1636 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1637 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1643 object
->backBuffer
= NULL
;
1646 if (object
->backBuffer
!= NULL
) {
1648 glDrawBuffer(GL_BACK
);
1649 checkGLcall("glDrawBuffer(GL_BACK)");
1652 /* Single buffering - draw to front buffer */
1654 glDrawBuffer(GL_FRONT
);
1655 checkGLcall("glDrawBuffer(GL_FRONT)");
1659 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1660 if (*(pPresentationParameters
->EnableAutoDepthStencil
) && hr
== WINED3D_OK
) {
1661 TRACE("Creating depth stencil buffer\n");
1662 if (This
->depthStencilBuffer
== NULL
) {
1663 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1665 object
->presentParms
.BackBufferWidth
,
1666 object
->presentParms
.BackBufferHeight
,
1667 object
->presentParms
.AutoDepthStencilFormat
,
1668 object
->presentParms
.MultiSampleType
,
1669 object
->presentParms
.MultiSampleQuality
,
1670 FALSE
/* FIXME: Discard */,
1671 &This
->depthStencilBuffer
,
1672 NULL
/* pShared (always null)*/ );
1673 if (This
->depthStencilBuffer
!= NULL
)
1674 IWineD3DSurface_SetContainer(This
->depthStencilBuffer
, 0);
1677 /** TODO: A check on width, height and multisample types
1678 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1679 ****************************/
1680 object
->wantsDepthStencilBuffer
= TRUE
;
1682 object
->wantsDepthStencilBuffer
= FALSE
;
1685 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1688 /*********************
1689 * init the default renderTarget management
1690 *******************/
1691 object
->drawable
= object
->win
;
1692 object
->render_ctx
= object
->glCtx
;
1694 if (hr
== WINED3D_OK
) {
1695 /*********************
1696 * Setup some defaults and clear down the buffers
1697 *******************/
1699 /** save current context and drawable **/
1700 oldContext
= glXGetCurrentContext();
1701 oldDrawable
= glXGetCurrentDrawable();
1703 TRACE("Activating context (display %p context %p drawable %ld)!\n", object
->display
, object
->glCtx
, object
->win
);
1704 if (glXMakeCurrent(object
->display
, object
->win
, object
->glCtx
) == False
) {
1705 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object
->display
, object
->glCtx
, object
->win
);
1707 checkGLcall("glXMakeCurrent");
1709 TRACE("Setting up the screen\n");
1710 /* Clear the screen */
1711 glClearColor(1.0, 0.0, 0.0, 0.0);
1712 checkGLcall("glClearColor");
1715 glClearStencil(0xffff);
1717 checkGLcall("glClear");
1719 glColor3f(1.0, 1.0, 1.0);
1720 checkGLcall("glColor3f");
1722 glEnable(GL_LIGHTING
);
1723 checkGLcall("glEnable");
1725 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER
, GL_TRUE
);
1726 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1728 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_COMBINE_EXT
);
1729 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1731 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL
, GL_SEPARATE_SPECULAR_COLOR
);
1732 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1734 /* switch back to the original context (if there was one)*/
1735 if (This
->swapchains
) {
1736 /** TODO: restore the context and drawable **/
1737 glXMakeCurrent(object
->display
, oldDrawable
, oldContext
);
1740 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1741 glPixelStorei(GL_PACK_ALIGNMENT
, SURFACE_ALIGNMENT
);
1742 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1743 glPixelStorei(GL_UNPACK_ALIGNMENT
, SURFACE_ALIGNMENT
);
1744 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1748 TRACE("Set swapchain to %p\n", object
);
1749 } else { /* something went wrong so clean up */
1750 IUnknown
* bufferParent
;
1751 if (object
->frontBuffer
) {
1753 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1754 IUnknown_Release(bufferParent
); /* once for the get parent */
1755 if (IUnknown_Release(bufferParent
) > 0) {
1756 FIXME("(%p) Something's still holding the front buffer\n",This
);
1759 if (object
->backBuffer
) {
1761 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1762 if(object
->backBuffer
[i
]) {
1763 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1764 IUnknown_Release(bufferParent
); /* once for the get parent */
1765 if (IUnknown_Release(bufferParent
) > 0) {
1766 FIXME("(%p) Something's still holding the back buffer\n",This
);
1770 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1771 object
->backBuffer
= NULL
;
1773 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1774 /* Clean up the context */
1775 /* check that we are the current context first (we shouldn't be though!) */
1776 if (object
->glCtx
!= 0) {
1777 if(glXGetCurrentContext() == object
->glCtx
) {
1778 glXMakeCurrent(object
->display
, None
, NULL
);
1780 glXDestroyContext(object
->display
, object
->glCtx
);
1782 HeapFree(GetProcessHeap(), 0, object
);
1789 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1790 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1791 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1792 TRACE("(%p)\n", This
);
1794 return This
->NumberOfSwapChains
;
1797 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1798 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1799 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1801 if(iSwapChain
< This
->NumberOfSwapChains
) {
1802 *pSwapChain
= This
->swapchains
[iSwapChain
];
1803 IWineD3DSwapChain_AddRef(*pSwapChain
);
1804 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1807 TRACE("Swapchain out of range\n");
1809 return WINED3DERR_INVALIDCALL
;
1814 * Vertex Declaration
1816 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, CONST VOID
* pDeclaration
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*parent
) {
1817 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1818 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1819 HRESULT hr
= WINED3D_OK
;
1820 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, pDeclaration
, ppVertexDeclaration
);
1821 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1824 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, (void *)pDeclaration
);
1829 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1830 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, CONST DWORD
*pDeclaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1831 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1832 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1833 HRESULT hr
= WINED3D_OK
;
1834 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1835 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1837 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1839 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1840 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1841 if (pDeclaration
!= NULL
) {
1842 IWineD3DVertexDeclaration
*vertexDeclaration
;
1843 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, pDeclaration
, &vertexDeclaration
,NULL
);
1844 if (WINED3D_OK
== hr
) {
1845 TRACE("(%p) : Setting vertex declaration to %p\n", This
, vertexDeclaration
);
1846 object
->vertexDeclaration
= vertexDeclaration
;
1848 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface
);
1849 IWineD3DVertexShader_Release(*ppVertexShader
);
1850 return WINED3DERR_INVALIDCALL
;
1854 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1856 if (WINED3D_OK
!= hr
) {
1857 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1858 IWineD3DVertexShader_Release(*ppVertexShader
);
1859 return WINED3DERR_INVALIDCALL
;
1862 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
1863 if(Usage
== WINED3DUSAGE_SOFTWAREVERTEXPROCESSING
) {
1874 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1875 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1876 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1877 HRESULT hr
= WINED3D_OK
;
1879 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1880 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1881 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1882 if (WINED3D_OK
== hr
) {
1883 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1885 WARN("(%p) : Failed to create pixel shader\n", This
);
1891 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1892 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1893 IWineD3DPaletteImpl
*object
;
1895 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1897 /* Create the new object */
1898 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1900 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1901 return E_OUTOFMEMORY
;
1904 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1906 object
->Flags
= Flags
;
1907 object
->parent
= Parent
;
1908 object
->wineD3DDevice
= This
;
1909 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1911 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1914 HeapFree( GetProcessHeap(), 0, object
);
1915 return E_OUTOFMEMORY
;
1918 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1920 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1924 *Palette
= (IWineD3DPalette
*) object
;
1929 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
1930 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1931 IWineD3DSwapChainImpl
*swapchain
;
1934 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
1935 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1937 /* TODO: Test if OpenGL is compiled in and loaded */
1939 /* Initialize the texture unit mapping to a 1:1 mapping */
1940 for(state
= 0; state
< MAX_SAMPLERS
; state
++) {
1941 This
->texUnitMap
[state
] = state
;
1943 This
->oneToOneTexUnitMap
= TRUE
;
1945 /* Setup the implicit swapchain */
1946 TRACE("Creating implicit swapchain\n");
1947 if (D3D_OK
!= D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
) || swapchain
== NULL
) {
1948 WARN("Failed to create implicit swapchain\n");
1949 return WINED3DERR_INVALIDCALL
;
1952 This
->NumberOfSwapChains
= 1;
1953 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1954 if(!This
->swapchains
) {
1955 ERR("Out of memory!\n");
1956 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1957 return E_OUTOFMEMORY
;
1959 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1961 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1962 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1963 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1966 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1967 This
->render_targets
[0] = swapchain
->frontBuffer
;
1969 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1970 /* Depth Stencil support */
1971 This
->stencilBufferTarget
= This
->depthStencilBuffer
;
1972 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
1973 set_depth_stencil_fbo(iface
, This
->depthStencilBuffer
);
1975 if (NULL
!= This
->stencilBufferTarget
) {
1976 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1979 /* Set up some starting GL setup */
1982 * Initialize openGL extension related variables
1983 * with Default values
1986 ((IWineD3DImpl
*) This
->wineD3D
)->isGLInfoValid
= IWineD3DImpl_FillGLCaps( This
->wineD3D
, swapchain
->display
);
1987 /* Setup all the devices defaults */
1988 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1990 IWineD3DImpl_CheckGraphicsMemory();
1994 /* Initialize our list of GLSL programs */
1995 list_init(&This
->glsl_shader_progs
);
1997 { /* Set a default viewport */
2001 vp
.Width
= *(pPresentationParameters
->BackBufferWidth
);
2002 vp
.Height
= *(pPresentationParameters
->BackBufferHeight
);
2005 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
2008 /* Initialize the current view state */
2009 This
->view_ident
= 1;
2010 This
->last_was_rhw
= 0;
2011 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2012 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2014 /* Clear the screen */
2015 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
, WINED3DCLEAR_STENCIL
|WINED3DCLEAR_ZBUFFER
|WINED3DCLEAR_TARGET
, 0x00, 1.0, 0);
2017 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
2018 * This might create a problem in 2 situations:
2019 * ->The D3D default value is 0, but the opengl default value is something else
2020 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
2022 for(state
= 0; state
<= STATE_HIGHEST
; state
++) {
2023 IWineD3DDeviceImpl_MarkStateDirty(This
, state
);
2026 This
->d3d_initialized
= TRUE
;
2030 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2031 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2034 TRACE("(%p)\n", This
);
2036 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2038 /* Delete the mouse cursor texture */
2039 if(This
->cursorTexture
) {
2041 glDeleteTextures(1, &This
->cursorTexture
);
2043 This
->cursorTexture
= 0;
2046 for(sampler
= 0; sampler
< GL_LIMITS(sampler_stages
); ++sampler
) {
2047 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2050 /* Release the buffers (with sanity checks)*/
2051 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2052 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2053 if(This
->depthStencilBuffer
!= This
->stencilBufferTarget
)
2054 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This
);
2056 This
->stencilBufferTarget
= NULL
;
2058 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2059 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2060 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2062 TRACE("Setting rendertarget to NULL\n");
2063 This
->render_targets
[0] = NULL
;
2065 if (This
->depthStencilBuffer
) {
2066 if(D3DCB_DestroyDepthStencilSurface(This
->depthStencilBuffer
) > 0) {
2067 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This
);
2069 This
->depthStencilBuffer
= NULL
;
2072 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2073 TRACE("Releasing the implicit swapchain %d\n", i
);
2074 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2075 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2079 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2080 This
->swapchains
= NULL
;
2081 This
->NumberOfSwapChains
= 0;
2083 This
->d3d_initialized
= FALSE
;
2087 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
2088 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2089 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
2091 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2092 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2093 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2096 This
->ddraw_fullscreen
= fullscreen
;
2099 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice
*iface
, DWORD Flags
, UINT Width
, UINT Height
, WINED3DFORMAT pixelformat
, LPVOID context
, D3DCB_ENUMDISPLAYMODESCALLBACK callback
) {
2100 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2104 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(pixelformat
);
2106 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This
, Flags
, Width
, Height
, pixelformat
, context
, callback
);
2108 for (i
= 0; EnumDisplaySettingsExW(NULL
, i
, &DevModeW
, 0); i
++) {
2109 /* Ignore some modes if a description was passed */
2110 if ( (Width
> 0) && (Width
!= DevModeW
.dmPelsWidth
)) continue;
2111 if ( (Height
> 0) && (Height
!= DevModeW
.dmPelsHeight
)) continue;
2112 if ( (pixelformat
!= WINED3DFMT_UNKNOWN
) && ( formatDesc
->bpp
!= DevModeW
.dmBitsPerPel
) ) continue;
2114 TRACE("Enumerating %dx%d@%s\n", DevModeW
.dmPelsWidth
, DevModeW
.dmPelsHeight
, debug_d3dformat(pixelformat_for_depth(DevModeW
.dmBitsPerPel
)));
2116 if (callback((IUnknown
*) This
, (UINT
) DevModeW
.dmPelsWidth
, (UINT
) DevModeW
.dmPelsHeight
, pixelformat_for_depth(DevModeW
.dmBitsPerPel
), 60.0, context
) == DDENUMRET_CANCEL
)
2123 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
2125 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2127 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
);
2130 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2132 /* Resize the screen even without a window:
2133 * The app could have unset it with SetCooperativeLevel, but not called
2134 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2135 * but we don't have any hwnd
2138 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2139 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
2140 if(devmode
.dmBitsPerPel
== 24) devmode
.dmBitsPerPel
= 32;
2141 devmode
.dmPelsWidth
= pMode
->Width
;
2142 devmode
.dmPelsHeight
= pMode
->Height
;
2144 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2145 if (pMode
->RefreshRate
!= 0) {
2146 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2149 /* Only change the mode if necessary */
2150 if( (This
->ddraw_width
== pMode
->Width
) &&
2151 (This
->ddraw_height
== pMode
->Height
) &&
2152 (This
->ddraw_format
== pMode
->Format
) &&
2153 (pMode
->RefreshRate
== 0) ) {
2157 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2158 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2159 if(devmode
.dmDisplayFrequency
!= 0) {
2160 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2161 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2162 devmode
.dmDisplayFrequency
= 0;
2163 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2165 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2166 return DDERR_INVALIDMODE
;
2170 /* Store the new values */
2171 This
->ddraw_width
= pMode
->Width
;
2172 This
->ddraw_height
= pMode
->Height
;
2173 This
->ddraw_format
= pMode
->Format
;
2175 /* Only do this with a window of course */
2176 if(This
->ddraw_window
)
2177 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
2179 /* And finally clip mouse to our screen */
2180 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2181 ClipCursor(&clip_rc
);
2186 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2187 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2188 *ppD3D
= This
->wineD3D
;
2189 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
2190 IWineD3D_AddRef(*ppD3D
);
2194 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2195 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2196 * into the video ram as possible and seeing how many fit
2197 * you can also get the correct initial value from nvidia and ATI's driver via X
2198 * texture memory is video memory + AGP memory
2199 *******************/
2200 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2201 static BOOL showfixmes
= TRUE
;
2203 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This
,
2204 (wined3d_settings
.emulated_textureram
/(1024*1024)),
2205 ((wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
) / (1024*1024)));
2208 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2209 (wined3d_settings
.emulated_textureram
/(1024*1024)),
2210 ((wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
) / (1024*1024)));
2211 /* return simulated texture memory left */
2212 return (wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
);
2220 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
2221 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2223 /* Update the current state block */
2224 This
->updateStateBlock
->changed
.fvf
= TRUE
;
2225 This
->updateStateBlock
->set
.fvf
= TRUE
;
2227 if(This
->updateStateBlock
->fvf
== fvf
) {
2228 TRACE("Application is setting the old fvf over, nothing to do\n");
2232 This
->updateStateBlock
->fvf
= fvf
;
2233 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
2234 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2239 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
2240 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2241 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
2242 *pfvf
= This
->stateBlock
->fvf
;
2247 * Get / Set Stream Source
2249 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
2250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2251 IWineD3DVertexBuffer
*oldSrc
;
2253 /**TODO: instance and index data, see
2254 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2256 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2259 /* D3d9 only, but shouldn't hurt d3d8 */
2262 streamFlags
= StreamNumber
&(WINED3DSTREAMSOURCE_INDEXEDDATA
| WINED3DSTREAMSOURCE_INSTANCEDATA
);
2264 if (streamFlags
& WINED3DSTREAMSOURCE_INDEXEDDATA
) {
2265 FIXME("stream index data not supported\n");
2267 if (streamFlags
& WINED3DSTREAMSOURCE_INDEXEDDATA
) {
2268 FIXME("stream instance data not supported\n");
2272 StreamNumber
&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA
| WINED3DSTREAMSOURCE_INSTANCEDATA
);
2274 if (StreamNumber
>= MAX_STREAMS
) {
2275 WARN("Stream out of range %d\n", StreamNumber
);
2276 return WINED3DERR_INVALIDCALL
;
2279 oldSrc
= This
->stateBlock
->streamSource
[StreamNumber
];
2280 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This
, StreamNumber
, oldSrc
, pStreamData
, Stride
);
2282 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
2283 This
->updateStateBlock
->set
.streamSource
[StreamNumber
] = TRUE
;
2285 if(oldSrc
== pStreamData
&&
2286 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2287 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
&&
2288 This
->updateStateBlock
->streamFlags
[StreamNumber
] == streamFlags
) {
2289 TRACE("Application is setting the old values over, nothing to do\n");
2293 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2295 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2296 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2298 This
->updateStateBlock
->streamFlags
[StreamNumber
] = streamFlags
;
2300 /* Handle recording of state blocks */
2301 if (This
->isRecordingState
) {
2302 TRACE("Recording... not performing anything\n");
2306 /* Same stream object: no action */
2307 if (oldSrc
== pStreamData
)
2310 /* Need to do a getParent and pass the reffs up */
2311 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2312 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2313 so for now, just count internally */
2314 if (pStreamData
!= NULL
) {
2315 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2316 InterlockedIncrement(&vbImpl
->bindCount
);
2318 if (oldSrc
!= NULL
) {
2319 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2322 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2327 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2331 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This
, StreamNumber
,
2332 This
->stateBlock
->streamSource
[StreamNumber
], This
->stateBlock
->streamStride
[StreamNumber
]);
2335 streamFlags
= StreamNumber
&(WINED3DSTREAMSOURCE_INDEXEDDATA
| WINED3DSTREAMSOURCE_INSTANCEDATA
);
2337 if (streamFlags
& WINED3DSTREAMSOURCE_INDEXEDDATA
) {
2338 FIXME("stream index data not supported\n");
2340 if (streamFlags
& WINED3DSTREAMSOURCE_INDEXEDDATA
) {
2341 FIXME("stream instance data not supported\n");
2345 StreamNumber
&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA
| WINED3DSTREAMSOURCE_INSTANCEDATA
);
2347 if (StreamNumber
>= MAX_STREAMS
) {
2348 WARN("Stream out of range %d\n", StreamNumber
);
2349 return WINED3DERR_INVALIDCALL
;
2351 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2352 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2354 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2357 if (*pStream
!= NULL
) {
2358 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2363 /*Should be quite easy, just an extension of vertexdata
2365 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2367 The divider is a bit odd though
2369 VertexOffset = StartVertex / Divider * StreamStride +
2370 VertexIndex / Divider * StreamStride + StreamOffset
2373 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2374 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2376 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2377 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2379 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2380 This
->updateStateBlock
->set
.streamFreq
[StreamNumber
] = TRUE
;
2381 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2383 if (This
->updateStateBlock
->streamFlags
[StreamNumber
] || This
->updateStateBlock
->streamFreq
[StreamNumber
] != 1) {
2384 FIXME("Stream indexing not fully supported\n");
2390 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2391 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2393 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2394 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2396 TRACE("(%p) : returning %d\n", This
, *Divider
);
2402 * Get / Set & Multiply Transform
2404 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2405 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2407 /* Most of this routine, comments included copied from ddraw tree initially: */
2408 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2410 /* Handle recording of state blocks */
2411 if (This
->isRecordingState
) {
2412 TRACE("Recording... not performing anything\n");
2413 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2414 This
->updateStateBlock
->set
.transform
[d3dts
] = TRUE
;
2415 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2420 * If the new matrix is the same as the current one,
2421 * we cut off any further processing. this seems to be a reasonable
2422 * optimization because as was noticed, some apps (warcraft3 for example)
2423 * tend towards setting the same matrix repeatedly for some reason.
2425 * From here on we assume that the new matrix is different, wherever it matters.
2427 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2428 TRACE("The app is setting the same matrix over again\n");
2431 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2435 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2436 where ViewMat = Camera space, WorldMat = world space.
2438 In OpenGL, camera and world space is combined into GL_MODELVIEW
2439 matrix. The Projection matrix stay projection matrix.
2442 /* Capture the times we can just ignore the change for now */
2443 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2444 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2445 /* Handled by the state manager */
2448 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2452 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2453 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2454 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2455 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2459 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2460 WINED3DMATRIX
*mat
= NULL
;
2463 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2464 * below means it will be recorded in a state block change, but it
2465 * works regardless where it is recorded.
2466 * If this is found to be wrong, change to StateBlock.
2468 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2469 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2471 if (State
< HIGHEST_TRANSFORMSTATE
)
2473 mat
= &This
->updateStateBlock
->transforms
[State
];
2475 FIXME("Unhandled transform state!!\n");
2478 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2480 /* Apply change via set transform - will reapply to eg. lights this way */
2481 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2487 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2488 you can reference any indexes you want as long as that number max are enabled at any
2489 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2490 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2491 but when recording, just build a chain pretty much of commands to be replayed. */
2493 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2495 PLIGHTINFOEL
*object
, *temp
;
2497 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2498 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2500 /* If recording state block, just add to end of lights chain */
2501 if (This
->isRecordingState
) {
2502 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PLIGHTINFOEL
));
2503 if (NULL
== object
) {
2504 return WINED3DERR_OUTOFVIDEOMEMORY
;
2506 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2507 object
->OriginalIndex
= Index
;
2508 object
->glIndex
= -1;
2509 object
->changed
= TRUE
;
2511 /* Add to the END of the chain of lights changes to be replayed */
2512 if (This
->updateStateBlock
->lights
== NULL
) {
2513 This
->updateStateBlock
->lights
= object
;
2515 temp
= This
->updateStateBlock
->lights
;
2516 while (temp
->next
!= NULL
) temp
=temp
->next
;
2517 temp
->next
= object
;
2519 TRACE("Recording... not performing anything more\n");
2523 /* Ok, not recording any longer so do real work */
2524 object
= This
->stateBlock
->lights
;
2525 while (object
!= NULL
&& object
->OriginalIndex
!= Index
) object
= object
->next
;
2527 /* If we didn't find it in the list of lights, time to add it */
2528 if (object
== NULL
) {
2529 PLIGHTINFOEL
*insertAt
,*prevPos
;
2531 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PLIGHTINFOEL
));
2532 if (NULL
== object
) {
2533 return WINED3DERR_OUTOFVIDEOMEMORY
;
2535 object
->OriginalIndex
= Index
;
2536 object
->glIndex
= -1;
2538 /* Add it to the front of list with the idea that lights will be changed as needed
2539 BUT after any lights currently assigned GL indexes */
2540 insertAt
= This
->stateBlock
->lights
;
2542 while (insertAt
!= NULL
&& insertAt
->glIndex
!= -1) {
2544 insertAt
= insertAt
->next
;
2547 if (insertAt
== NULL
&& prevPos
== NULL
) { /* Start of list */
2548 This
->stateBlock
->lights
= object
;
2549 } else if (insertAt
== NULL
) { /* End of list */
2550 prevPos
->next
= object
;
2551 object
->prev
= prevPos
;
2552 } else { /* Middle of chain */
2553 if (prevPos
== NULL
) {
2554 This
->stateBlock
->lights
= object
;
2556 prevPos
->next
= object
;
2558 object
->prev
= prevPos
;
2559 object
->next
= insertAt
;
2560 insertAt
->prev
= object
;
2564 /* Initialize the object */
2565 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
,
2566 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2567 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2568 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2569 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2570 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2571 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2573 /* Save away the information */
2574 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2576 switch (pLight
->Type
) {
2577 case WINED3DLIGHT_POINT
:
2579 object
->lightPosn
[0] = pLight
->Position
.x
;
2580 object
->lightPosn
[1] = pLight
->Position
.y
;
2581 object
->lightPosn
[2] = pLight
->Position
.z
;
2582 object
->lightPosn
[3] = 1.0f
;
2583 object
->cutoff
= 180.0f
;
2587 case WINED3DLIGHT_DIRECTIONAL
:
2589 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2590 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2591 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2592 object
->lightPosn
[3] = 0.0;
2593 object
->exponent
= 0.0f
;
2594 object
->cutoff
= 180.0f
;
2597 case WINED3DLIGHT_SPOT
:
2599 object
->lightPosn
[0] = pLight
->Position
.x
;
2600 object
->lightPosn
[1] = pLight
->Position
.y
;
2601 object
->lightPosn
[2] = pLight
->Position
.z
;
2602 object
->lightPosn
[3] = 1.0;
2605 object
->lightDirn
[0] = pLight
->Direction
.x
;
2606 object
->lightDirn
[1] = pLight
->Direction
.y
;
2607 object
->lightDirn
[2] = pLight
->Direction
.z
;
2608 object
->lightDirn
[3] = 1.0;
2611 * opengl-ish and d3d-ish spot lights use too different models for the
2612 * light "intensity" as a function of the angle towards the main light direction,
2613 * so we only can approximate very roughly.
2614 * however spot lights are rather rarely used in games (if ever used at all).
2615 * furthermore if still used, probably nobody pays attention to such details.
2617 if (pLight
->Falloff
== 0) {
2620 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2622 if (rho
< 0.0001) rho
= 0.0001f
;
2623 object
->exponent
= -0.3/log(cos(rho
/2));
2624 if (object
->exponent
> 128.0) {
2625 object
->exponent
= 128.0;
2627 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2633 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2636 /* Update the live definitions if the light is currently assigned a glIndex */
2637 if (object
->glIndex
!= -1) {
2638 setup_light(iface
, object
->glIndex
, object
);
2643 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2644 PLIGHTINFOEL
*lightInfo
= NULL
;
2645 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2646 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2648 /* Locate the light in the live lights */
2649 lightInfo
= This
->stateBlock
->lights
;
2650 while (lightInfo
!= NULL
&& lightInfo
->OriginalIndex
!= Index
) lightInfo
= lightInfo
->next
;
2652 if (lightInfo
== NULL
) {
2653 TRACE("Light information requested but light not defined\n");
2654 return WINED3DERR_INVALIDCALL
;
2657 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2662 * Get / Set Light Enable
2663 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2665 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2666 PLIGHTINFOEL
*lightInfo
= NULL
;
2667 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2668 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2670 /* Tests show true = 128...not clear why */
2672 Enable
= Enable
? 128: 0;
2674 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2675 if (This
->isRecordingState
) {
2676 lightInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PLIGHTINFOEL
));
2677 if (NULL
== lightInfo
) {
2678 return WINED3DERR_OUTOFVIDEOMEMORY
;
2680 lightInfo
->OriginalIndex
= Index
;
2681 lightInfo
->glIndex
= -1;
2682 lightInfo
->enabledChanged
= TRUE
;
2683 lightInfo
->lightEnabled
= Enable
;
2685 /* Add to the END of the chain of lights changes to be replayed */
2686 if (This
->updateStateBlock
->lights
== NULL
) {
2687 This
->updateStateBlock
->lights
= lightInfo
;
2689 PLIGHTINFOEL
*temp
= This
->updateStateBlock
->lights
;
2690 while (temp
->next
!= NULL
) temp
=temp
->next
;
2691 temp
->next
= lightInfo
;
2693 TRACE("Recording... not performing anything more\n");
2697 /* Not recording... So, locate the light in the live lights */
2698 lightInfo
= This
->stateBlock
->lights
;
2699 while (lightInfo
!= NULL
&& lightInfo
->OriginalIndex
!= Index
) lightInfo
= lightInfo
->next
;
2701 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2702 if (lightInfo
== NULL
) {
2704 TRACE("Light enabled requested but light not defined, so defining one!\n");
2705 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2707 /* Search for it again! Should be fairly quick as near head of list */
2708 lightInfo
= This
->stateBlock
->lights
;
2709 while (lightInfo
!= NULL
&& lightInfo
->OriginalIndex
!= Index
) lightInfo
= lightInfo
->next
;
2710 if (lightInfo
== NULL
) {
2711 FIXME("Adding default lights has failed dismally\n");
2712 return WINED3DERR_INVALIDCALL
;
2716 /* OK, we now have a light... */
2719 /* If we are disabling it, check it was enabled, and
2720 still only do something if it has assigned a glIndex (which it should have!) */
2721 if ((lightInfo
->lightEnabled
) && (lightInfo
->glIndex
!= -1)) {
2722 TRACE("Disabling light set up at gl idx %d\n", lightInfo
->glIndex
);
2724 glDisable(GL_LIGHT0
+ lightInfo
->glIndex
);
2725 checkGLcall("glDisable GL_LIGHT0+Index");
2728 TRACE("Nothing to do as light was not enabled\n");
2730 lightInfo
->lightEnabled
= Enable
;
2733 /* We are enabling it. If it is enabled, it's really simple */
2734 if (lightInfo
->lightEnabled
) {
2736 TRACE("Nothing to do as light was enabled\n");
2738 /* If it already has a glIndex, it's still simple */
2739 } else if (lightInfo
->glIndex
!= -1) {
2740 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo
->glIndex
);
2741 lightInfo
->lightEnabled
= Enable
;
2743 glEnable(GL_LIGHT0
+ lightInfo
->glIndex
);
2744 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2747 /* Otherwise got to find space - lights are ordered gl indexes first */
2749 PLIGHTINFOEL
*bsf
= NULL
;
2750 PLIGHTINFOEL
*pos
= This
->stateBlock
->lights
;
2751 PLIGHTINFOEL
*prev
= NULL
;
2755 /* Try to minimize changes as much as possible */
2756 while (pos
!= NULL
&& pos
->glIndex
!= -1 && Index
< This
->maxConcurrentLights
) {
2758 /* Try to remember which index can be replaced if necessary */
2759 if (bsf
==NULL
&& !pos
->lightEnabled
) {
2760 /* Found a light we can replace, save as best replacement */
2764 /* Step to next space */
2770 /* If we have too many active lights, fail the call */
2771 if ((Index
== This
->maxConcurrentLights
) && (bsf
== NULL
)) {
2772 FIXME("Program requests too many concurrent lights\n");
2773 return WINED3DERR_INVALIDCALL
;
2775 /* If we have allocated all lights, but not all are enabled,
2776 reuse one which is not enabled */
2777 } else if (Index
== This
->maxConcurrentLights
) {
2778 /* use bsf - Simply swap the new light and the BSF one */
2779 PLIGHTINFOEL
*bsfNext
= bsf
->next
;
2780 PLIGHTINFOEL
*bsfPrev
= bsf
->prev
;
2783 if (lightInfo
->next
!= NULL
) lightInfo
->next
->prev
= bsf
;
2784 if (bsf
->prev
!= NULL
) {
2785 bsf
->prev
->next
= lightInfo
;
2787 This
->stateBlock
->lights
= lightInfo
;
2790 /* If not side by side, lots of chains to update */
2791 if (bsf
->next
!= lightInfo
) {
2792 lightInfo
->prev
->next
= bsf
;
2793 bsf
->next
->prev
= lightInfo
;
2794 bsf
->next
= lightInfo
->next
;
2795 bsf
->prev
= lightInfo
->prev
;
2796 lightInfo
->next
= bsfNext
;
2797 lightInfo
->prev
= bsfPrev
;
2801 bsf
->prev
= lightInfo
;
2802 bsf
->next
= lightInfo
->next
;
2803 lightInfo
->next
= bsf
;
2804 lightInfo
->prev
= bsfPrev
;
2809 glIndex
= bsf
->glIndex
;
2811 lightInfo
->glIndex
= glIndex
;
2812 lightInfo
->lightEnabled
= Enable
;
2814 /* Finally set up the light in gl itself */
2815 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo
->glIndex
);
2817 setup_light(iface
, glIndex
, lightInfo
);
2818 glEnable(GL_LIGHT0
+ glIndex
);
2819 checkGLcall("glEnable GL_LIGHT0 new setup");
2822 /* If we reached the end of the allocated lights, with space in the
2823 gl lights, setup a new light */
2824 } else if (pos
->glIndex
== -1) {
2826 /* We reached the end of the allocated gl lights, so already
2827 know the index of the next one! */
2829 lightInfo
->glIndex
= glIndex
;
2830 lightInfo
->lightEnabled
= Enable
;
2832 /* In an ideal world, it's already in the right place */
2833 if (lightInfo
->prev
== NULL
|| lightInfo
->prev
->glIndex
!=-1) {
2834 /* No need to move it */
2836 /* Remove this light from the list */
2837 lightInfo
->prev
->next
= lightInfo
->next
;
2838 if (lightInfo
->next
!= NULL
) {
2839 lightInfo
->next
->prev
= lightInfo
->prev
;
2842 /* Add in at appropriate place (inbetween prev and pos) */
2843 lightInfo
->prev
= prev
;
2844 lightInfo
->next
= pos
;
2846 This
->stateBlock
->lights
= lightInfo
;
2848 prev
->next
= lightInfo
;
2851 pos
->prev
= lightInfo
;
2855 /* Finally set up the light in gl itself */
2856 TRACE("Defining new light at gl idx %d\n", lightInfo
->glIndex
);
2858 setup_light(iface
, glIndex
, lightInfo
);
2859 glEnable(GL_LIGHT0
+ glIndex
);
2860 checkGLcall("glEnable GL_LIGHT0 new setup");
2869 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2871 PLIGHTINFOEL
*lightInfo
= NULL
;
2872 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2873 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2875 /* Locate the light in the live lights */
2876 lightInfo
= This
->stateBlock
->lights
;
2877 while (lightInfo
!= NULL
&& lightInfo
->OriginalIndex
!= Index
) lightInfo
= lightInfo
->next
;
2879 if (lightInfo
== NULL
) {
2880 TRACE("Light enabled state requested but light not defined\n");
2881 return WINED3DERR_INVALIDCALL
;
2883 *pEnable
= lightInfo
->lightEnabled
;
2888 * Get / Set Clip Planes
2890 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2891 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2892 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2894 /* Validate Index */
2895 if (Index
>= GL_LIMITS(clipplanes
)) {
2896 TRACE("Application has requested clipplane this device doesn't support\n");
2897 return WINED3DERR_INVALIDCALL
;
2900 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2901 This
->updateStateBlock
->set
.clipplane
[Index
] = TRUE
;
2902 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2903 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2904 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2905 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2907 /* Handle recording of state blocks */
2908 if (This
->isRecordingState
) {
2909 TRACE("Recording... not performing anything\n");
2917 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2918 glMatrixMode(GL_MODELVIEW
);
2920 glLoadMatrixf((float *) &This
->stateBlock
->transforms
[WINED3DTS_VIEW
].u
.m
[0][0]);
2922 TRACE("Clipplane [%f,%f,%f,%f]\n",
2923 This
->updateStateBlock
->clipplane
[Index
][0],
2924 This
->updateStateBlock
->clipplane
[Index
][1],
2925 This
->updateStateBlock
->clipplane
[Index
][2],
2926 This
->updateStateBlock
->clipplane
[Index
][3]);
2927 glClipPlane(GL_CLIP_PLANE0
+ Index
, This
->updateStateBlock
->clipplane
[Index
]);
2928 checkGLcall("glClipPlane");
2936 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2937 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2938 TRACE("(%p) : for idx %d\n", This
, Index
);
2940 /* Validate Index */
2941 if (Index
>= GL_LIMITS(clipplanes
)) {
2942 TRACE("Application has requested clipplane this device doesn't support\n");
2943 return WINED3DERR_INVALIDCALL
;
2946 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2947 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2948 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2949 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2954 * Get / Set Clip Plane Status
2955 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2957 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2958 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2959 FIXME("(%p) : stub\n", This
);
2960 if (NULL
== pClipStatus
) {
2961 return WINED3DERR_INVALIDCALL
;
2963 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2964 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2968 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2969 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2970 FIXME("(%p) : stub\n", This
);
2971 if (NULL
== pClipStatus
) {
2972 return WINED3DERR_INVALIDCALL
;
2974 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2975 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2980 * Get / Set Material
2982 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2983 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2985 This
->updateStateBlock
->changed
.material
= TRUE
;
2986 This
->updateStateBlock
->set
.material
= TRUE
;
2987 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2989 /* Handle recording of state blocks */
2990 if (This
->isRecordingState
) {
2991 TRACE("Recording... not performing anything\n");
2996 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2997 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2998 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2999 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3000 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3001 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3002 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3003 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3004 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3006 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT
, (float*) &This
->updateStateBlock
->material
.Ambient
);
3007 checkGLcall("glMaterialfv(GL_AMBIENT)");
3008 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, (float*) &This
->updateStateBlock
->material
.Diffuse
);
3009 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3011 /* Only change material color if specular is enabled, otherwise it is set to black */
3012 if (This
->stateBlock
->renderState
[WINED3DRS_SPECULARENABLE
]) {
3013 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, (float*) &This
->updateStateBlock
->material
.Specular
);
3014 checkGLcall("glMaterialfv(GL_SPECULAR");
3016 float black
[4] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
3017 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, &black
[0]);
3018 checkGLcall("glMaterialfv(GL_SPECULAR");
3020 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, (float*) &This
->updateStateBlock
->material
.Emissive
);
3021 checkGLcall("glMaterialfv(GL_EMISSION)");
3022 glMaterialf(GL_FRONT_AND_BACK
, GL_SHININESS
, This
->updateStateBlock
->material
.Power
);
3023 checkGLcall("glMaterialf(GL_SHININESS");
3029 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3030 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3031 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
3032 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3033 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3034 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3035 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3036 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3037 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3038 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3039 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3040 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3048 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
,
3049 UINT BaseVertexIndex
) {
3050 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3051 IWineD3DIndexBuffer
*oldIdxs
;
3052 UINT oldBaseIndex
= This
->updateStateBlock
->baseVertexIndex
;
3054 TRACE("(%p) : Setting to %p, base %d\n", This
, pIndexData
, BaseVertexIndex
);
3055 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3057 This
->updateStateBlock
->changed
.indices
= TRUE
;
3058 This
->updateStateBlock
->set
.indices
= TRUE
;
3059 This
->updateStateBlock
->pIndexData
= pIndexData
;
3060 This
->updateStateBlock
->baseVertexIndex
= BaseVertexIndex
;
3062 /* Handle recording of state blocks */
3063 if (This
->isRecordingState
) {
3064 TRACE("Recording... not performing anything\n");
3068 /* So far only the base vertex index is tracked */
3069 if(BaseVertexIndex
!= oldBaseIndex
) {
3070 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3075 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
, UINT
* pBaseVertexIndex
) {
3076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3078 *ppIndexData
= This
->stateBlock
->pIndexData
;
3080 /* up ref count on ppindexdata */
3082 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
3083 *pBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
3084 TRACE("(%p) index data set to %p + %u\n", This
, ppIndexData
, This
->stateBlock
->baseVertexIndex
);
3086 TRACE("(%p) No index data set\n", This
);
3088 TRACE("Returning %p %d\n", *ppIndexData
, *pBaseVertexIndex
);
3093 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3094 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice
*iface
, UINT BaseIndex
) {
3095 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3096 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3098 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3099 TRACE("Application is setting the old value over, nothing to do\n");
3103 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3105 if (This
->isRecordingState
) {
3106 TRACE("Recording... not performing anything\n");
3109 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3114 * Get / Set Viewports
3116 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3119 TRACE("(%p)\n", This
);
3120 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3121 This
->updateStateBlock
->set
.viewport
= TRUE
;
3122 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
3124 /* Handle recording of state blocks */
3125 if (This
->isRecordingState
) {
3126 TRACE("Recording... not performing anything\n");
3130 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3131 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3133 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3138 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3139 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3140 TRACE("(%p)\n", This
);
3141 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
3146 * Get / Set Render States
3147 * TODO: Verify against dx9 definitions
3149 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3151 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3152 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3154 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3156 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
3157 This
->updateStateBlock
->set
.renderState
[State
] = TRUE
;
3158 This
->updateStateBlock
->renderState
[State
] = Value
;
3160 /* Handle recording of state blocks */
3161 if (This
->isRecordingState
) {
3162 TRACE("Recording... not performing anything\n");
3166 /* Compared here and not before the assignment to allow proper stateblock recording */
3167 if(Value
== oldValue
) {
3168 TRACE("Application is setting the old value over, nothing to do\n");
3170 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3176 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3177 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3178 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3179 *pValue
= This
->stateBlock
->renderState
[State
];
3184 * Get / Set Sampler States
3185 * TODO: Verify against dx9 definitions
3188 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3189 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3190 DWORD oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3193 * SetSampler is designed to allow for more than the standard up to 8 textures
3194 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3195 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3197 * http://developer.nvidia.com/object/General_FAQ.html#t6
3199 * There are two new settings for GForce
3201 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3202 * and the texture one:
3203 * GL_MAX_TEXTURE_COORDS_ARB.
3204 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3206 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
3207 if(Sampler
> GL_LIMITS(sampler_stages
) || Sampler
< 0 || Type
> WINED3D_HIGHEST_SAMPLER_STATE
|| Type
< 0) {
3208 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3209 Sampler
, debug_d3dsamplerstate(Type
), Type
, GL_LIMITS(sampler_stages
), WINED3D_HIGHEST_SAMPLER_STATE
);
3210 return WINED3DERR_INVALIDCALL
;
3213 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This
, Sampler
,
3214 debug_d3dsamplerstate(Type
), Type
, Value
);
3215 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3216 This
->updateStateBlock
->set
.samplerState
[Sampler
][Type
] = Value
;
3217 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
3219 /* Handle recording of state blocks */
3220 if (This
->isRecordingState
) {
3221 TRACE("Recording... not performing anything\n");
3225 if(oldValue
== Value
) {
3226 TRACE("Application is setting the old value over, nothing to do\n");
3230 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3235 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3236 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3237 /** TODO: check that sampler is in range **/
3238 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3239 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This
, Sampler
, Type
, *Value
);
3244 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3245 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3249 This
->updateStateBlock
->set
.scissorRect
= TRUE
;
3250 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3251 memcpy(&This
->updateStateBlock
->scissorRect
, pRect
, sizeof(*pRect
));
3253 if(This
->isRecordingState
) {
3254 TRACE("Recording... not performing anything\n");
3258 GetClientRect(((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->win_handle
, &windowRect
);
3259 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3260 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3262 winHeight
= windowRect
.bottom
- windowRect
.top
;
3263 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->bottom
- winHeight
,
3264 pRect
->right
- pRect
->left
, pRect
->bottom
- pRect
->top
);
3266 glScissor(pRect
->left
, winHeight
- pRect
->bottom
, pRect
->right
- pRect
->left
, pRect
->bottom
- pRect
->top
);
3267 checkGLcall("glScissor");
3273 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3274 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3276 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
3277 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3281 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3282 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3283 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3285 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3287 This
->updateStateBlock
->vertexDecl
= pDecl
;
3288 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3289 This
->updateStateBlock
->set
.vertexDecl
= TRUE
;
3291 if (This
->isRecordingState
) {
3292 TRACE("Recording... not performing anything\n");
3294 } else if(pDecl
== oldDecl
) {
3295 /* Checked after the assignment to allow proper stateblock recording */
3296 TRACE("Application is setting the old declaration over, nothing to do\n");
3300 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3304 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3305 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3307 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3309 *ppDecl
= This
->stateBlock
->vertexDecl
;
3310 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3314 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3315 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3316 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3318 This
->updateStateBlock
->vertexShader
= pShader
;
3319 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3320 This
->updateStateBlock
->set
.vertexShader
= TRUE
;
3322 if (This
->isRecordingState
) {
3323 TRACE("Recording... not performing anything\n");
3325 } else if(oldShader
== pShader
) {
3326 /* Checked here to allow proper stateblock recording */
3327 TRACE("App is setting the old shader over, nothing to do\n");
3331 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3333 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3338 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3339 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3341 if (NULL
== ppShader
) {
3342 return WINED3DERR_INVALIDCALL
;
3344 *ppShader
= This
->stateBlock
->vertexShader
;
3345 if( NULL
!= *ppShader
)
3346 IWineD3DVertexShader_AddRef(*ppShader
);
3348 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3352 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3353 IWineD3DDevice
*iface
,
3355 CONST BOOL
*srcData
,
3358 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3359 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3361 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3362 iface
, srcData
, start
, count
);
3364 if (srcData
== NULL
|| cnt
< 0)
3365 return WINED3DERR_INVALIDCALL
;
3367 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3368 for (i
= 0; i
< cnt
; i
++)
3369 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3371 for (i
= start
; i
< cnt
+ start
; ++i
) {
3372 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
3373 This
->updateStateBlock
->set
.vertexShaderConstantsB
[i
] = TRUE
;
3376 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3381 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3382 IWineD3DDevice
*iface
,
3387 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3388 int cnt
= min(count
, MAX_CONST_B
- start
);
3390 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3391 iface
, dstData
, start
, count
);
3393 if (dstData
== NULL
|| cnt
< 0)
3394 return WINED3DERR_INVALIDCALL
;
3396 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3400 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3401 IWineD3DDevice
*iface
,
3406 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3407 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3409 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3410 iface
, srcData
, start
, count
);
3412 if (srcData
== NULL
|| cnt
< 0)
3413 return WINED3DERR_INVALIDCALL
;
3415 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3416 for (i
= 0; i
< cnt
; i
++)
3417 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3418 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3420 for (i
= start
; i
< cnt
+ start
; ++i
) {
3421 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
3422 This
->updateStateBlock
->set
.vertexShaderConstantsI
[i
] = TRUE
;
3425 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3430 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3431 IWineD3DDevice
*iface
,
3436 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3437 int cnt
= min(count
, MAX_CONST_I
- start
);
3439 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3440 iface
, dstData
, start
, count
);
3442 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3443 return WINED3DERR_INVALIDCALL
;
3445 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3449 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3450 IWineD3DDevice
*iface
,
3452 CONST
float *srcData
,
3455 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3456 int i
, cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3458 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3459 iface
, srcData
, start
, count
);
3461 if (srcData
== NULL
|| ((signed int) GL_LIMITS(vshader_constantsF
) - (signed int) start
) <= (signed int) 0)
3462 return WINED3DERR_INVALIDCALL
;
3464 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, cnt
* sizeof(float) * 4);
3465 for (i
= 0; i
< cnt
; i
++)
3466 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3467 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3469 for (i
= start
; i
< cnt
+ start
; ++i
) {
3470 if (!This
->updateStateBlock
->set
.vertexShaderConstantsF
[i
]) {
3471 constant_entry
*ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry
));
3473 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3474 This
->updateStateBlock
->set
.vertexShaderConstantsF
[i
] = TRUE
;
3476 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3479 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3484 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3485 IWineD3DDevice
*iface
,
3490 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3491 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3493 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3494 iface
, dstData
, start
, count
);
3496 if (dstData
== NULL
|| cnt
< 0)
3497 return WINED3DERR_INVALIDCALL
;
3499 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3503 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3505 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3506 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3510 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3512 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3513 * it is never called.
3516 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3517 * that would be really messy and require shader recompilation
3518 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3519 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3520 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3521 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3523 if(This
->stateBlock
->pixelShader
|| This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3524 if(This
->oneToOneTexUnitMap
) {
3525 TRACE("Not touching 1:1 map\n");
3528 TRACE("Restoring 1:1 texture unit mapping\n");
3529 /* Restore a 1:1 mapping */
3530 for(i
= 0; i
< MAX_SAMPLERS
; i
++) {
3531 if(This
->texUnitMap
[i
] != i
) {
3532 This
->texUnitMap
[i
] = i
;
3533 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3534 markTextureStagesDirty(This
, i
);
3537 This
->oneToOneTexUnitMap
= TRUE
;
3540 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3541 * First, see if we can succeed at all
3544 for(i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3545 if(This
->stateBlock
->textures
[i
] == NULL
) tex
++;
3548 if(GL_LIMITS(textures
) + tex
< This
->stateBlock
->lowest_disabled_stage
) {
3549 FIXME("Too many bound textures to support the combiner settings\n");
3553 /* Now work out the mapping */
3555 This
->oneToOneTexUnitMap
= FALSE
;
3556 WARN("Non 1:1 mapping UNTESTED!\n");
3557 for(i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3558 /* Skip NULL textures */
3559 if (!This
->stateBlock
->textures
[i
]) {
3560 /* Map to -1, so the check below doesn't fail if a non-NULL
3561 * texture is set on this stage */
3562 TRACE("Mapping texture stage %d to -1\n", i
);
3563 This
->texUnitMap
[i
] = -1;
3568 TRACE("Mapping texture stage %d to unit %d\n", i
, tex
);
3569 if(This
->texUnitMap
[i
] != tex
) {
3570 This
->texUnitMap
[i
] = tex
;
3571 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3572 markTextureStagesDirty(This
, i
);
3580 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3581 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3582 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3583 This
->updateStateBlock
->pixelShader
= pShader
;
3584 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3585 This
->updateStateBlock
->set
.pixelShader
= TRUE
;
3587 /* Handle recording of state blocks */
3588 if (This
->isRecordingState
) {
3589 TRACE("Recording... not performing anything\n");
3592 if (This
->isRecordingState
) {
3593 TRACE("Recording... not performing anything\n");
3597 if(pShader
== oldShader
) {
3598 TRACE("App is setting the old pixel shader over, nothing to do\n");
3602 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3603 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3605 /* Rebuild the texture unit mapping if nvrc's are supported */
3606 if(GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
3607 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3613 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3614 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3616 if (NULL
== ppShader
) {
3617 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3618 return WINED3DERR_INVALIDCALL
;
3621 *ppShader
= This
->stateBlock
->pixelShader
;
3622 if (NULL
!= *ppShader
) {
3623 IWineD3DPixelShader_AddRef(*ppShader
);
3625 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3629 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3630 IWineD3DDevice
*iface
,
3632 CONST BOOL
*srcData
,
3635 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3636 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3638 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3639 iface
, srcData
, start
, count
);
3641 if (srcData
== NULL
|| cnt
< 0)
3642 return WINED3DERR_INVALIDCALL
;
3644 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3645 for (i
= 0; i
< cnt
; i
++)
3646 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3648 for (i
= start
; i
< cnt
+ start
; ++i
) {
3649 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3650 This
->updateStateBlock
->set
.pixelShaderConstantsB
[i
] = TRUE
;
3653 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3658 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3659 IWineD3DDevice
*iface
,
3664 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3665 int cnt
= min(count
, MAX_CONST_B
- start
);
3667 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3668 iface
, dstData
, start
, count
);
3670 if (dstData
== NULL
|| cnt
< 0)
3671 return WINED3DERR_INVALIDCALL
;
3673 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3677 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3678 IWineD3DDevice
*iface
,
3683 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3684 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3686 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3687 iface
, srcData
, start
, count
);
3689 if (srcData
== NULL
|| cnt
< 0)
3690 return WINED3DERR_INVALIDCALL
;
3692 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3693 for (i
= 0; i
< cnt
; i
++)
3694 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3695 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3697 for (i
= start
; i
< cnt
+ start
; ++i
) {
3698 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3699 This
->updateStateBlock
->set
.pixelShaderConstantsI
[i
] = TRUE
;
3702 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3707 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3708 IWineD3DDevice
*iface
,
3713 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3714 int cnt
= min(count
, MAX_CONST_I
- start
);
3716 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3717 iface
, dstData
, start
, count
);
3719 if (dstData
== NULL
|| cnt
< 0)
3720 return WINED3DERR_INVALIDCALL
;
3722 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3726 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3727 IWineD3DDevice
*iface
,
3729 CONST
float *srcData
,
3732 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3733 int i
, cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3735 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3736 iface
, srcData
, start
, count
);
3738 if (srcData
== NULL
|| cnt
< 0)
3739 return WINED3DERR_INVALIDCALL
;
3741 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, cnt
* sizeof(float) * 4);
3742 for (i
= 0; i
< cnt
; i
++)
3743 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3744 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3746 for (i
= start
; i
< cnt
+ start
; ++i
) {
3747 if (!This
->updateStateBlock
->set
.pixelShaderConstantsF
[i
]) {
3748 constant_entry
*ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry
));
3750 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3751 This
->updateStateBlock
->set
.pixelShaderConstantsF
[i
] = TRUE
;
3753 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3756 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3761 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3762 IWineD3DDevice
*iface
,
3767 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3768 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3770 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3771 iface
, dstData
, start
, count
);
3773 if (dstData
== NULL
|| cnt
< 0)
3774 return WINED3DERR_INVALIDCALL
;
3776 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3780 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3782 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, DWORD SrcFVF
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3783 char *dest_ptr
, *dest_conv
= NULL
;
3785 DWORD DestFVF
= dest
->fvf
;
3787 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3791 if (SrcFVF
& WINED3DFVF_NORMAL
) {
3792 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3795 if ( (SrcFVF
& WINED3DFVF_POSITION_MASK
) != WINED3DFVF_XYZ
) {
3796 ERR("Source has no position mask\n");
3797 return WINED3DERR_INVALIDCALL
;
3800 /* We might access VBOs from this code, so hold the lock */
3803 if (dest
->resource
.allocatedMemory
== NULL
) {
3804 /* This may happen if we do direct locking into a vbo. Unlikely,
3805 * but theoretically possible(ddraw processvertices test)
3807 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3808 if(!dest
->resource
.allocatedMemory
) {
3810 ERR("Out of memory\n");
3811 return E_OUTOFMEMORY
;
3815 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3816 checkGLcall("glBindBufferARB");
3817 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3819 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3821 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3822 checkGLcall("glUnmapBufferARB");
3826 /* Get a pointer into the destination vbo(create one if none exists) and
3827 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3829 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3834 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3835 dest_conv
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
));
3837 ERR("glMapBuffer failed\n");
3838 /* Continue without storing converted vertices */
3843 * a) WINED3DRS_CLIPPING is enabled
3844 * b) WINED3DVOP_CLIP is passed
3846 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3847 static BOOL warned
= FALSE
;
3849 * The clipping code is not quite correct. Some things need
3850 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3851 * so disable clipping for now.
3852 * (The graphics in Half-Life are broken, and my processvertices
3853 * test crashes with IDirect3DDevice3)
3859 FIXME("Clipping is broken and disabled for now\n");
3861 } else doClip
= FALSE
;
3862 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3864 dest_conv
= ((char *) dest_conv
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3867 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3870 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3871 WINED3DTS_PROJECTION
,
3873 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3874 WINED3DTS_WORLDMATRIX(0),
3877 TRACE("View mat:\n");
3878 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
);
3879 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
);
3880 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
);
3881 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
);
3883 TRACE("Proj mat:\n");
3884 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
);
3885 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
);
3886 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
);
3887 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
);
3889 TRACE("World mat:\n");
3890 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
);
3891 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
);
3892 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
);
3893 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
);
3895 /* Get the viewport */
3896 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3897 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3898 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3900 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3901 multiply_matrix(&mat
,&proj_mat
,&mat
);
3903 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3905 for (i
= 0; i
< dwCount
; i
+= 1) {
3906 unsigned int tex_index
;
3908 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3909 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3910 /* The position first */
3912 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
3914 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3916 /* Multiplication with world, view and projection matrix */
3917 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
);
3918 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
);
3919 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
);
3920 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
);
3922 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3924 /* WARNING: The following things are taken from d3d7 and were not yet checked
3925 * against d3d8 or d3d9!
3928 /* Clipping conditions: From
3929 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3931 * A vertex is clipped if it does not match the following requirements
3935 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3937 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3938 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3943 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3944 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3947 /* "Normal" viewport transformation (not clipped)
3948 * 1) The values are divided by rhw
3949 * 2) The y axis is negative, so multiply it with -1
3950 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3951 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3952 * 4) Multiply x with Width/2 and add Width/2
3953 * 5) The same for the height
3954 * 6) Add the viewpoint X and Y to the 2D coordinates and
3955 * The minimum Z value to z
3956 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3958 * Well, basically it's simply a linear transformation into viewport
3970 z
*= vp
.MaxZ
- vp
.MinZ
;
3972 x
+= vp
.Width
/ 2 + vp
.X
;
3973 y
+= vp
.Height
/ 2 + vp
.Y
;
3978 /* That vertex got clipped
3979 * Contrary to OpenGL it is not dropped completely, it just
3980 * undergoes a different calculation.
3982 TRACE("Vertex got clipped\n");
3989 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3990 * outside of the main vertex buffer memory. That needs some more
3995 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3998 ( (float *) dest_ptr
)[0] = x
;
3999 ( (float *) dest_ptr
)[1] = y
;
4000 ( (float *) dest_ptr
)[2] = z
;
4001 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4003 dest_ptr
+= 3 * sizeof(float);
4005 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4006 dest_ptr
+= sizeof(float);
4011 ( (float *) dest_conv
)[0] = x
* w
;
4012 ( (float *) dest_conv
)[1] = y
* w
;
4013 ( (float *) dest_conv
)[2] = z
* w
;
4014 ( (float *) dest_conv
)[3] = w
;
4016 dest_conv
+= 3 * sizeof(float);
4018 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4019 dest_conv
+= sizeof(float);
4023 if (DestFVF
& WINED3DFVF_PSIZE
) {
4024 dest_ptr
+= sizeof(DWORD
);
4025 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4027 if (DestFVF
& WINED3DFVF_NORMAL
) {
4029 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
4030 /* AFAIK this should go into the lighting information */
4031 FIXME("Didn't expect the destination to have a normal\n");
4032 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4034 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4038 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4040 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
4042 static BOOL warned
= FALSE
;
4045 ERR("No diffuse color in source, but destination has one\n");
4049 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4050 dest_ptr
+= sizeof(DWORD
);
4053 *( (DWORD
*) dest_conv
) = 0xffffffff;
4054 dest_conv
+= sizeof(DWORD
);
4058 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4060 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4061 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4062 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4063 dest_conv
+= sizeof(DWORD
);
4068 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4069 /* What's the color value in the feedback buffer? */
4071 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
4073 static BOOL warned
= FALSE
;
4076 ERR("No specular color in source, but destination has one\n");
4080 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4081 dest_ptr
+= sizeof(DWORD
);
4084 *( (DWORD
*) dest_conv
) = 0xFF000000;
4085 dest_conv
+= sizeof(DWORD
);
4089 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4091 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4092 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4093 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4094 dest_conv
+= sizeof(DWORD
);
4099 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4101 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
4102 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
4104 ERR("No source texture, but destination requests one\n");
4105 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4106 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4109 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4111 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4118 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4119 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4126 #undef copy_and_next
4128 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexBuffer
* pVertexDecl
, DWORD Flags
) {
4129 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4130 IWineD3DVertexBufferImpl
*SrcImpl
= (IWineD3DVertexBufferImpl
*) pVertexDecl
;
4131 WineDirect3DVertexStridedData strided
;
4132 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4135 WARN("NULL source vertex buffer\n");
4136 return WINED3DERR_INVALIDCALL
;
4138 /* We don't need the source vbo because this buffer is only used as
4139 * a source for ProcessVertices. Avoid wasting resources by converting the
4140 * buffer and loading the VBO
4143 TRACE("Releasing the source vbo, it won't be needed\n");
4145 if(!SrcImpl
->resource
.allocatedMemory
) {
4146 /* Rescue the data from the buffer */
4148 SrcImpl
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, SrcImpl
->resource
.size
);
4149 if(!SrcImpl
->resource
.allocatedMemory
) {
4150 ERR("Out of memory\n");
4151 return E_OUTOFMEMORY
;
4155 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, SrcImpl
->vbo
));
4156 checkGLcall("glBindBufferARB");
4158 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4160 memcpy(SrcImpl
->resource
.allocatedMemory
, src
, SrcImpl
->resource
.size
);
4163 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4164 checkGLcall("glUnmapBufferARB");
4169 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, 0));
4170 checkGLcall("glBindBufferARB");
4171 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl
->vbo
));
4172 checkGLcall("glDeleteBuffersARB");
4178 memset(&strided
, 0, sizeof(strided
));
4179 primitiveConvertFVFtoOffset(SrcImpl
->fvf
, get_flexible_vertex_size(SrcImpl
->fvf
), SrcImpl
->resource
.allocatedMemory
+ get_flexible_vertex_size(SrcImpl
->fvf
) * SrcStartIndex
, &strided
, 0, 0);
4181 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, SrcImpl
->fvf
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
4185 * Get / Set Texture Stage States
4186 * TODO: Verify against dx9 definitions
4188 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4189 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4190 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4192 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4194 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4196 /* Reject invalid texture units */
4197 if (Stage
>= GL_LIMITS(texture_stages
)) {
4198 TRACE("Attempt to access invalid texture rejected\n");
4199 return WINED3DERR_INVALIDCALL
;
4202 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
4203 This
->updateStateBlock
->set
.textureState
[Stage
][Type
] = TRUE
;
4204 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4206 if (This
->isRecordingState
) {
4207 TRACE("Recording... not performing anything\n");
4211 /* Checked after the assignments to allow proper stateblock recording */
4212 if(oldValue
== Value
) {
4213 TRACE("App is setting the old value over, nothing to do\n");
4217 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4218 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4219 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4220 * Changes in other states are important on disabled stages too
4225 if(Type
== WINED3DTSS_COLOROP
) {
4228 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4229 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4230 * they have to be disabled
4232 * The current stage is dirtified below.
4234 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4235 TRACE("Additionally dirtifying stage %d\n", i
);
4236 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4238 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4239 TRACE("New lowest disabled: %d\n", Stage
);
4240 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4241 /* Previously disabled stage enabled. Stages above it may need enabling
4242 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4243 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4245 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4248 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4249 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4252 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
4253 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4255 This
->stateBlock
->lowest_disabled_stage
= i
;
4256 TRACE("New lowest disabled: %d\n", i
);
4258 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4259 /* TODO: Built a stage -> texture unit mapping for register combiners */
4263 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4265 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4266 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4267 * will call FindTexUnitMap too.
4269 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4270 IWineD3DDeviceImpl_FindTexUnitMap(This
);
4275 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4277 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4278 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4285 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
4287 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4288 IWineD3DBaseTexture
*oldTexture
;
4290 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
4291 TRACE("(%p) : Stage(%d), Texture (%p)\n", This
, Stage
, pTexture
);
4293 #if 0 /* TODO: check so vertex textures */
4294 if (Stage
>= D3DVERTEXTEXTURESAMPLER
&& Stage
<= D3DVERTEXTEXTURESAMPLER3
){
4295 This
->updateStateBlock
->vertexTextures
[Stage
- D3DVERTEXTEXTURESAMPLER
] = pTexture
;
4300 /* Reject invalid texture units */
4301 if (Stage
>= GL_LIMITS(sampler_stages
) || Stage
< 0) {
4302 WARN("Attempt to access invalid texture rejected\n");
4303 return WINED3DERR_INVALIDCALL
;
4306 if(pTexture
!= NULL
) {
4307 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4309 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
4310 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
4311 return WINED3DERR_INVALIDCALL
;
4313 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
4316 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
4317 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
4319 This
->updateStateBlock
->set
.textures
[Stage
] = TRUE
;
4320 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
4321 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
4322 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
4324 /* Handle recording of state blocks */
4325 if (This
->isRecordingState
) {
4326 TRACE("Recording... not performing anything\n");
4330 if(oldTexture
== pTexture
) {
4331 TRACE("App is setting the same texture again, nothing to do\n");
4335 /** NOTE: MSDN says that setTexture increases the reference count,
4336 * and the the application nust set the texture back to null (or have a leaky application),
4337 * This means we should pass the refcount up to the parent
4338 *******************************/
4339 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
4340 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
4341 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
4343 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
4344 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4345 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4346 * so the COLOROP and ALPHAOP have to be dirtified.
4348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4349 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4351 if(bindCount
== 1) {
4352 new->baseTexture
.sampler
= Stage
;
4354 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4358 if (NULL
!= oldTexture
) {
4359 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
4360 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
4362 IWineD3DBaseTexture_Release(oldTexture
);
4363 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
4364 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
4365 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
4368 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
4370 /* Have to do a search for the other sampler(s) where the texture is bound to
4371 * Shouldn't happen as long as apps bind a texture only to one stage
4373 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4374 for(i
= 0; i
< GL_LIMITS(sampler_stages
); i
++) {
4375 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
4376 old
->baseTexture
.sampler
= i
;
4383 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
4385 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4386 * pixel shader is used
4388 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
4389 IWineD3DDeviceImpl_FindTexUnitMap(This
);
4395 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4396 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4397 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This
, Stage
, ppTexture
);
4399 /* Reject invalid texture units */
4400 if (Stage
>= GL_LIMITS(sampler_stages
)) {
4401 TRACE("Attempt to access invalid texture rejected\n");
4402 return WINED3DERR_INVALIDCALL
;
4404 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4406 IWineD3DBaseTexture_AddRef(*ppTexture
);
4414 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4415 IWineD3DSurface
**ppBackBuffer
) {
4416 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4417 IWineD3DSwapChain
*swapChain
;
4420 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4422 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4423 if (hr
== WINED3D_OK
) {
4424 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4425 IWineD3DSwapChain_Release(swapChain
);
4427 *ppBackBuffer
= NULL
;
4432 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4433 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4434 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4435 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
4438 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4439 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4440 IWineD3DSwapChain
*swapChain
;
4443 if(iSwapChain
> 0) {
4444 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4445 if (hr
== WINED3D_OK
) {
4446 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4447 IWineD3DSwapChain_Release(swapChain
);
4449 FIXME("(%p) Error getting display mode\n", This
);
4452 /* Don't read the real display mode,
4453 but return the stored mode instead. X11 can't change the color
4454 depth, and some apps are pretty angry if they SetDisplayMode from
4455 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4457 Also don't relay to the swapchain because with ddraw it's possible
4458 that there isn't a swapchain at all */
4459 pMode
->Width
= This
->ddraw_width
;
4460 pMode
->Height
= This
->ddraw_height
;
4461 pMode
->Format
= This
->ddraw_format
;
4462 pMode
->RefreshRate
= 0;
4469 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4471 TRACE("(%p)->(%p)\n", This
, hWnd
);
4473 This
->ddraw_window
= hWnd
;
4477 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4478 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4479 TRACE("(%p)->(%p)\n", This
, hWnd
);
4481 *hWnd
= This
->ddraw_window
;
4486 * Stateblock related functions
4489 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4490 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4491 IWineD3DStateBlockImpl
*object
;
4492 HRESULT temp_result
;
4494 TRACE("(%p)\n", This
);
4496 if (This
->isRecordingState
) {
4497 return WINED3DERR_INVALIDCALL
;
4500 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4501 if (NULL
== object
) {
4502 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4503 return E_OUTOFMEMORY
;
4505 TRACE("(%p) created object %p\n", This
, object
);
4506 object
->wineD3DDevice
= This
;
4507 /** FIXME: object->parent = parent; **/
4508 object
->parent
= NULL
;
4509 object
->blockType
= WINED3DSBT_ALL
;
4511 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4513 temp_result
= allocate_shader_constants(object
);
4514 if (WINED3D_OK
!= temp_result
)
4517 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4518 This
->updateStateBlock
= object
;
4519 This
->isRecordingState
= TRUE
;
4521 TRACE("(%p) recording stateblock %p\n",This
, object
);
4525 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4526 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4528 if (!This
->isRecordingState
) {
4529 FIXME("(%p) not recording! returning error\n", This
);
4530 *ppStateBlock
= NULL
;
4531 return WINED3DERR_INVALIDCALL
;
4534 *ppStateBlock
= (IWineD3DStateBlock
*)This
->updateStateBlock
;
4535 This
->isRecordingState
= FALSE
;
4536 This
->updateStateBlock
= This
->stateBlock
;
4537 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4538 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4539 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4544 * Scene related functions
4546 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4547 /* At the moment we have no need for any functionality at the beginning
4549 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4550 TRACE("(%p) : stub\n", This
);
4554 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4555 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4556 TRACE("(%p)\n", This
);
4558 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4560 checkGLcall("glFlush");
4562 TRACE("End Scene\n");
4563 /* If we're using FBOs this isn't needed */
4564 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
&& This
->render_targets
[0] != NULL
) {
4566 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4567 IUnknown
*targetContainer
= NULL
;
4568 if (WINED3D_OK
== IWineD3DSurface_GetContainer(This
->render_targets
[0], &IID_IWineD3DBaseTexture
, (void **)&targetContainer
)
4569 || WINED3D_OK
== IWineD3DSurface_GetContainer(This
->render_targets
[0], &IID_IWineD3DDevice
, (void **)&targetContainer
)) {
4570 TRACE("(%p) : Texture rendertarget %p\n", This
,This
->render_targets
[0]);
4571 /** always dirtify for now. we must find a better way to see that surface have been modified
4572 (Modifications should will only occur via draw-primitive, but we do need better locking
4573 switching to render-to-texture should remove the overhead though.
4575 IWineD3DSurface_SetPBufferState(This
->render_targets
[0], TRUE
/* inPBuffer */, FALSE
/* inTexture */);
4576 IWineD3DSurface_AddDirtyRect(This
->render_targets
[0], NULL
);
4577 IWineD3DSurface_PreLoad(This
->render_targets
[0]);
4578 IWineD3DSurface_SetPBufferState(This
->render_targets
[0], FALSE
/* inPBuffer */, FALSE
/* inTexture */);
4579 IUnknown_Release(targetContainer
);
4582 This
->sceneEnded
= TRUE
;
4587 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4588 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4589 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4590 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4591 IWineD3DSwapChain
*swapChain
= NULL
;
4593 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4595 TRACE("(%p) Presenting the frame\n", This
);
4597 for(i
= 0 ; i
< swapchains
; i
++) {
4599 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4600 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4601 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4602 IWineD3DSwapChain_Release(swapChain
);
4608 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4609 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4610 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4612 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4613 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4614 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4615 GLbitfield glMask
= 0;
4616 GLboolean old_ztest
;
4617 GLfloat old_z_clear_value
;
4618 GLint old_stencil_clear_value
;
4619 GLfloat old_color_clear_value
[4];
4621 CONST WINED3DRECT
* curRect
;
4623 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This
,
4624 Count
, pRects
, Flags
, Z
, Stencil
);
4628 glEnable(GL_SCISSOR_TEST
);
4629 checkGLcall("glEnable GL_SCISSOR_TEST");
4631 if (Count
> 0 && pRects
) {
4637 /* Only set the values up once, as they are not changing */
4638 if (Flags
& WINED3DCLEAR_STENCIL
) {
4639 glGetIntegerv(GL_STENCIL_CLEAR_VALUE
, &old_stencil_clear_value
);
4640 glClearStencil(Stencil
);
4641 checkGLcall("glClearStencil");
4642 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4643 glStencilMask(0xFFFFFFFF);
4646 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4647 glGetBooleanv(GL_DEPTH_WRITEMASK
, &old_ztest
);
4648 glDepthMask(GL_TRUE
);
4649 glGetFloatv(GL_DEPTH_CLEAR_VALUE
, &old_z_clear_value
);
4651 checkGLcall("glClearDepth");
4652 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4655 if (Flags
& WINED3DCLEAR_TARGET
) {
4656 TRACE("Clearing screen with glClear to color %x\n", Color
);
4657 glGetFloatv(GL_COLOR_CLEAR_VALUE
, old_color_clear_value
);
4658 glClearColor(D3DCOLOR_R(Color
),
4662 checkGLcall("glClearColor");
4664 /* Clear ALL colors! */
4665 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4666 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4669 /* Now process each rect in turn */
4670 for (i
= 0; i
< Count
|| i
== 0; i
++) {
4673 /* Note gl uses lower left, width/height */
4674 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
, curRect
,
4675 curRect
->x1
, curRect
->y1
, curRect
->x2
, curRect
->y2
,
4676 curRect
->x1
, (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
- curRect
->y2
),
4677 curRect
->x2
- curRect
->x1
, curRect
->y2
- curRect
->y1
);
4678 glScissor(curRect
->x1
, (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
- curRect
->y2
),
4679 curRect
->x2
- curRect
->x1
, curRect
->y2
- curRect
->y1
);
4680 checkGLcall("glScissor");
4682 glScissor(This
->stateBlock
->viewport
.X
,
4683 (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
-
4684 (This
->stateBlock
->viewport
.Y
+ This
->stateBlock
->viewport
.Height
)),
4685 This
->stateBlock
->viewport
.Width
,
4686 This
->stateBlock
->viewport
.Height
);
4687 checkGLcall("glScissor");
4690 /* Clear the selected rectangle (or full screen) */
4692 checkGLcall("glClear");
4694 /* Step to the next rectangle */
4695 if (curRect
) curRect
= curRect
+ sizeof(WINED3DRECT
);
4698 /* Restore the old values (why..?) */
4699 if (Flags
& WINED3DCLEAR_STENCIL
) {
4700 glClearStencil(old_stencil_clear_value
);
4701 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4703 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4704 glDepthMask(old_ztest
);
4705 glClearDepth(old_z_clear_value
);
4707 if (Flags
& WINED3DCLEAR_TARGET
) {
4708 glClearColor(old_color_clear_value
[0],
4709 old_color_clear_value
[1],
4710 old_color_clear_value
[2],
4711 old_color_clear_value
[3]);
4712 glColorMask(This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4713 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4714 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4715 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4718 glDisable(GL_SCISSOR_TEST
);
4719 checkGLcall("glDisable");
4728 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4729 UINT PrimitiveCount
) {
4731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4732 This
->stateBlock
->streamIsUP
= FALSE
;
4734 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4735 debug_d3dprimitivetype(PrimitiveType
),
4736 StartVertex
, PrimitiveCount
);
4738 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4739 This
->stateBlock
->loadBaseVertexIndex
= 0;
4740 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4742 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4743 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4744 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4748 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4749 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4750 WINED3DPRIMITIVETYPE PrimitiveType
,
4751 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4753 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4755 IWineD3DIndexBuffer
*pIB
;
4756 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4758 pIB
= This
->stateBlock
->pIndexData
;
4759 This
->stateBlock
->streamIsUP
= FALSE
;
4761 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
4762 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4763 minIndex
, NumVertices
, startIndex
, primCount
);
4765 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
4766 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
4772 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4773 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4774 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4777 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
4778 idxStride
, ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
4783 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4784 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
4785 UINT VertexStreamZeroStride
) {
4786 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4788 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
4789 debug_d3dprimitivetype(PrimitiveType
),
4790 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4792 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4793 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4794 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4795 This
->stateBlock
->streamIsUP
= TRUE
;
4796 This
->stateBlock
->loadBaseVertexIndex
= 0;
4798 /* TODO: Only mark dirty if drawing from a different UP address */
4799 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4801 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
4802 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
4804 /* MSDN specifies stream zero settings must be set to NULL */
4805 This
->stateBlock
->streamStride
[0] = 0;
4806 This
->stateBlock
->streamSource
[0] = NULL
;
4808 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4809 * the new stream sources or use UP drawing again
4814 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4815 UINT MinVertexIndex
, UINT NumVertices
,
4816 UINT PrimitiveCount
, CONST
void* pIndexData
,
4817 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
4818 UINT VertexStreamZeroStride
) {
4820 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4822 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4823 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4824 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
4825 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4827 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
4833 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4834 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4835 This
->stateBlock
->streamIsUP
= TRUE
;
4836 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4838 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4839 This
->stateBlock
->baseVertexIndex
= 0;
4840 This
->stateBlock
->loadBaseVertexIndex
= 0;
4841 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4842 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4844 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
4846 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4847 This
->stateBlock
->streamSource
[0] = NULL
;
4848 This
->stateBlock
->streamStride
[0] = 0;
4849 This
->stateBlock
->pIndexData
= NULL
;
4850 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4851 * SetStreamSource to specify a vertex buffer
4857 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
4858 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4860 /* Mark the state dirty until we have nicer tracking
4861 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4864 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4865 This
->stateBlock
->baseVertexIndex
= 0;
4866 This
->up_strided
= DrawPrimStrideData
;
4867 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
4868 This
->up_strided
= NULL
;
4871 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4872 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
4873 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4874 HRESULT hr
= WINED3D_OK
;
4875 WINED3DRESOURCETYPE sourceType
;
4876 WINED3DRESOURCETYPE destinationType
;
4879 /* TODO: think about moving the code into IWineD3DBaseTexture */
4881 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
4883 /* verify that the source and destination textures aren't NULL */
4884 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
4885 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4886 This
, pSourceTexture
, pDestinationTexture
);
4887 hr
= WINED3DERR_INVALIDCALL
;
4890 if (pSourceTexture
== pDestinationTexture
) {
4891 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4892 This
, pSourceTexture
, pDestinationTexture
);
4893 hr
= WINED3DERR_INVALIDCALL
;
4895 /* Verify that the source and destination textures are the same type */
4896 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
4897 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
4899 if (sourceType
!= destinationType
) {
4900 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4902 hr
= WINED3DERR_INVALIDCALL
;
4905 /* check that both textures have the identical numbers of levels */
4906 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
4907 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
4908 hr
= WINED3DERR_INVALIDCALL
;
4911 if (WINED3D_OK
== hr
) {
4913 /* Make sure that the destination texture is loaded */
4914 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
4916 /* Update every surface level of the texture */
4917 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
4919 switch (sourceType
) {
4920 case WINED3DRTYPE_TEXTURE
:
4922 IWineD3DSurface
*srcSurface
;
4923 IWineD3DSurface
*destSurface
;
4925 for (i
= 0 ; i
< levels
; ++i
) {
4926 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
4927 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
4928 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
4929 IWineD3DSurface_Release(srcSurface
);
4930 IWineD3DSurface_Release(destSurface
);
4931 if (WINED3D_OK
!= hr
) {
4932 WARN("(%p) : Call to update surface failed\n", This
);
4938 case WINED3DRTYPE_CUBETEXTURE
:
4940 IWineD3DSurface
*srcSurface
;
4941 IWineD3DSurface
*destSurface
;
4942 WINED3DCUBEMAP_FACES faceType
;
4944 for (i
= 0 ; i
< levels
; ++i
) {
4945 /* Update each cube face */
4946 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
4947 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
4948 if (WINED3D_OK
!= hr
) {
4949 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
4951 TRACE("Got srcSurface %p\n", srcSurface
);
4953 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
4954 if (WINED3D_OK
!= hr
) {
4955 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
4957 TRACE("Got desrSurface %p\n", destSurface
);
4959 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
4960 IWineD3DSurface_Release(srcSurface
);
4961 IWineD3DSurface_Release(destSurface
);
4962 if (WINED3D_OK
!= hr
) {
4963 WARN("(%p) : Call to update surface failed\n", This
);
4970 #if 0 /* TODO: Add support for volume textures */
4971 case WINED3DRTYPE_VOLUMETEXTURE
:
4973 IWineD3DVolume srcVolume
= NULL
;
4974 IWineD3DSurface destVolume
= NULL
;
4976 for (i
= 0 ; i
< levels
; ++i
) {
4977 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
4978 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
4979 hr
= IWineD3DFoo_UpdateVolume(iface
, srcVolume
, NULL
, destVolume
, NULL
);
4980 IWineD3DVolume_Release(srcSurface
);
4981 IWineD3DVolume_Release(destSurface
);
4982 if (WINED3D_OK
!= hr
) {
4983 WARN("(%p) : Call to update volume failed\n", This
);
4991 FIXME("(%p) : Unsupported source and destination type\n", This
);
4992 hr
= WINED3DERR_INVALIDCALL
;
4999 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice
*iface
, IWineD3DSurface
*pRenderTarget
, IWineD3DSurface
*pSurface
) {
5000 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5001 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5002 * NOTE It may be best to move the code into surface to occomplish this
5003 ****************************************/
5005 WINED3DSURFACE_DESC surfaceDesc
;
5006 unsigned int surfaceWidth
, surfaceHeight
;
5007 glDescriptor
*targetGlDescription
= NULL
;
5008 glDescriptor
*surfaceGlDescription
= NULL
;
5009 IWineD3DSwapChainImpl
*container
= NULL
;
5011 IWineD3DSurface_GetGlDesc(pRenderTarget
, &targetGlDescription
);
5012 IWineD3DSurface_GetGlDesc(pSurface
, &surfaceGlDescription
);
5013 memset(&surfaceDesc
, 0, sizeof(surfaceDesc
));
5015 surfaceDesc
.Width
= &surfaceWidth
;
5016 surfaceDesc
.Height
= &surfaceHeight
;
5017 IWineD3DSurface_GetDesc(pSurface
, &surfaceDesc
);
5018 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5020 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5021 IWineD3DSurface_GetContainer(pRenderTarget
, &IID_IWineD3DSwapChain
, (void **)&container
);
5023 /* TODO: opengl Context switching for swapchains etc... */
5024 if (NULL
!= container
|| pRenderTarget
== This
->render_targets
[0] || pRenderTarget
== This
->depthStencilBuffer
) {
5025 if (NULL
!= container
&& (pRenderTarget
== container
->backBuffer
[0])) {
5026 glReadBuffer(GL_BACK
);
5027 vcheckGLcall("glReadBuffer(GL_BACK)");
5028 } else if ((NULL
!= container
&& (pRenderTarget
== container
->frontBuffer
)) || (pRenderTarget
== This
->render_targets
[0])) {
5029 glReadBuffer(GL_FRONT
);
5030 vcheckGLcall("glReadBuffer(GL_FRONT)");
5031 } else if (pRenderTarget
== This
->depthStencilBuffer
) {
5032 FIXME("Reading of depthstencil not yet supported\n");
5039 surfaceGlDescription
->glFormat
,
5040 surfaceGlDescription
->glType
,
5041 (void *)IWineD3DSurface_GetData(pSurface
));
5042 vcheckGLcall("glReadPixels(...)");
5043 if(NULL
!= container
){
5044 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) container
);
5047 IWineD3DBaseTexture
*container
;
5048 GLenum textureDimensions
= GL_TEXTURE_2D
;
5050 if (WINED3D_OK
== IWineD3DSurface_GetContainer(pSurface
, &IID_IWineD3DBaseTexture
, (void **)&container
)) {
5051 textureDimensions
= IWineD3DBaseTexture_GetTextureDimensions(container
);
5052 IWineD3DBaseTexture_Release(container
);
5054 /* TODO: 2D -> Cube surface coppies etc.. */
5055 if (surfaceGlDescription
->target
!= textureDimensions
) {
5056 FIXME("(%p) : Texture dimension mismatch\n", This
);
5058 glEnable(textureDimensions
);
5059 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5060 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5061 glBindTexture(targetGlDescription
->target
, targetGlDescription
->textureName
);
5062 vcheckGLcall("glBindTexture");
5063 glGetTexImage(surfaceGlDescription
->target
,
5064 surfaceGlDescription
->level
,
5065 surfaceGlDescription
->glFormat
,
5066 surfaceGlDescription
->glType
,
5067 (void *)IWineD3DSurface_GetData(pSurface
));
5068 glDisable(textureDimensions
);
5069 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5076 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5077 IWineD3DSwapChain
*swapChain
;
5079 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5080 if(hr
== WINED3D_OK
) {
5081 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5082 IWineD3DSwapChain_Release(swapChain
);
5087 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5088 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5089 /* return a sensible default */
5091 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5092 FIXME("(%p) : stub\n", This
);
5096 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5097 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5099 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5100 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5101 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5102 return WINED3DERR_INVALIDCALL
;
5104 for (j
= 0; j
< 256; ++j
) {
5105 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5106 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5107 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5108 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5110 TRACE("(%p) : returning\n", This
);
5114 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5115 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5117 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5118 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5119 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5120 return WINED3DERR_INVALIDCALL
;
5122 for (j
= 0; j
< 256; ++j
) {
5123 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5124 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5125 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5126 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5128 TRACE("(%p) : returning\n", This
);
5132 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5133 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5134 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5135 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
5136 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5137 return WINED3DERR_INVALIDCALL
;
5139 /*TODO: stateblocks */
5140 This
->currentPalette
= PaletteNumber
;
5141 TRACE("(%p) : returning\n", This
);
5145 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5146 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5147 if (PaletteNumber
== NULL
) {
5148 WARN("(%p) : returning Invalid Call\n", This
);
5149 return WINED3DERR_INVALIDCALL
;
5151 /*TODO: stateblocks */
5152 *PaletteNumber
= This
->currentPalette
;
5153 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5157 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5159 static BOOL showFixmes
= TRUE
;
5161 FIXME("(%p) : stub\n", This
);
5165 This
->softwareVertexProcessing
= bSoftware
;
5170 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5171 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5172 static BOOL showFixmes
= TRUE
;
5174 FIXME("(%p) : stub\n", This
);
5177 return This
->softwareVertexProcessing
;
5181 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5182 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5183 IWineD3DSwapChain
*swapChain
;
5186 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5188 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
5189 if(hr
== WINED3D_OK
){
5190 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5191 IWineD3DSwapChain_Release(swapChain
);
5193 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5199 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5200 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5201 static BOOL showfixmes
= TRUE
;
5202 if(nSegments
!= 0.0f
) {
5204 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5211 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5212 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5213 static BOOL showfixmes
= TRUE
;
5215 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5221 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5222 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5223 /** TODO: remove casts to IWineD3DSurfaceImpl
5224 * NOTE: move code to surface to accomplish this
5225 ****************************************/
5226 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5227 int srcWidth
, srcHeight
;
5228 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5229 WINED3DFORMAT destFormat
, srcFormat
;
5231 int srcLeft
, destLeft
, destTop
;
5232 WINED3DPOOL srcPool
, destPool
;
5234 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5235 glDescriptor
*glDescription
= NULL
;
5236 GLenum textureDimensions
= GL_TEXTURE_2D
;
5237 IWineD3DBaseTexture
*baseTexture
;
5239 WINED3DSURFACE_DESC winedesc
;
5241 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5242 memset(&winedesc
, 0, sizeof(winedesc
));
5243 winedesc
.Width
= &srcSurfaceWidth
;
5244 winedesc
.Height
= &srcSurfaceHeight
;
5245 winedesc
.Pool
= &srcPool
;
5246 winedesc
.Format
= &srcFormat
;
5248 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5250 winedesc
.Width
= &destSurfaceWidth
;
5251 winedesc
.Height
= &destSurfaceHeight
;
5252 winedesc
.Pool
= &destPool
;
5253 winedesc
.Format
= &destFormat
;
5254 winedesc
.Size
= &destSize
;
5256 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5258 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5259 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5260 return WINED3DERR_INVALIDCALL
;
5263 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5264 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5265 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5267 /* Get the update surface description */
5268 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5271 /* Make sure the surface is loaded and up to date */
5272 IWineD3DSurface_PreLoad(pDestinationSurface
);
5274 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
5278 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5279 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5280 srcHeight
= pSourceRect
? pSourceRect
->top
- pSourceRect
->bottom
: srcSurfaceHeight
;
5281 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5282 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5283 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5286 /* This function doesn't support compressed textures
5287 the pitch is just bytesPerPixel * width */
5288 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5289 rowoffset
= (srcSurfaceWidth
- srcWidth
) * pSrcSurface
->bytesPerPixel
;
5290 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
5291 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5293 /* TODO DXT formats */
5295 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5296 offset
+= pSourceRect
->top
* srcWidth
* pSrcSurface
->bytesPerPixel
;
5298 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5300 ,glDescription
->level
5305 ,glDescription
->glFormat
5306 ,glDescription
->glType
5307 ,IWineD3DSurface_GetData(pSourceSurface
)
5311 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5313 /* need to lock the surface to get the data */
5314 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5317 /* TODO: Cube and volume support */
5319 /* not a whole row so we have to do it a line at a time */
5322 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5323 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5325 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
5327 glTexSubImage2D(glDescription
->target
5328 ,glDescription
->level
5333 ,glDescription
->glFormat
5334 ,glDescription
->glType
5335 ,data
/* could be quicker using */
5340 } else { /* Full width, so just write out the whole texture */
5342 if (WINED3DFMT_DXT1
== destFormat
||
5343 WINED3DFMT_DXT2
== destFormat
||
5344 WINED3DFMT_DXT3
== destFormat
||
5345 WINED3DFMT_DXT4
== destFormat
||
5346 WINED3DFMT_DXT5
== destFormat
) {
5347 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
5348 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
5349 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5350 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5351 } if (destFormat
!= srcFormat
) {
5352 FIXME("Updating mixed format compressed texture is not curretly support\n");
5354 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
5355 glDescription
->level
,
5356 glDescription
->glFormatInternal
,
5361 IWineD3DSurface_GetData(pSourceSurface
));
5364 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5369 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
) {
5371 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5372 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5373 data returned by GetData non-power2 width/height with hardware non-power2
5374 pow2Width/height are set to surface width height, repacking isn't needed so it
5375 doesn't matter which function gets called. */
5376 glTexSubImage2D(glDescription
->target
5377 ,glDescription
->level
5382 ,glDescription
->glFormat
5383 ,glDescription
->glType
5384 ,IWineD3DSurface_GetData(pSourceSurface
)
5388 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5389 glTexSubImage2D(glDescription
->target
5390 ,glDescription
->level
5393 ,((IWineD3DSurfaceImpl
*)pSourceSurface
)->pow2Width
5394 ,((IWineD3DSurfaceImpl
*)pSourceSurface
)->pow2Height
5395 ,glDescription
->glFormat
5396 ,glDescription
->glType
5397 ,IWineD3DSurface_GetData(pSourceSurface
)
5403 checkGLcall("glTexSubImage2D");
5404 ((IWineD3DSurfaceImpl
*)pDestinationSurface
)->Flags
|= SFLAG_GLDIRTY
;
5406 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5407 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5408 * surface bigger than it needs to be hmm.. */
5409 if (WINED3D_OK
== IWineD3DSurface_GetContainer(pDestinationSurface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
)) {
5410 textureDimensions
= IWineD3DBaseTexture_GetTextureDimensions(baseTexture
);
5411 IWineD3DBaseTexture_Release(baseTexture
);
5414 glDisable(textureDimensions
); /* This needs to be managed better.... */
5420 /* Implementation details at http://developer.nvidia.com/attach/6494
5422 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5423 hmm.. no longer supported use
5424 OpenGL evaluators or tessellate surfaces within your application.
5427 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5428 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5429 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5430 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5431 FIXME("(%p) : Stub\n", This
);
5436 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5437 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5438 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5439 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5440 FIXME("(%p) : Stub\n", This
);
5444 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5445 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5446 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5447 FIXME("(%p) : Stub\n", This
);
5451 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5452 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5453 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5455 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This
, pSurface
, pRect
, color
);
5457 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5458 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5459 return WINED3DERR_INVALIDCALL
;
5462 /* Just forward this to the DirectDraw blitting engine */
5463 memset(&BltFx
, 0, sizeof(BltFx
));
5464 BltFx
.dwSize
= sizeof(BltFx
);
5465 BltFx
.u5
.dwFillColor
= color
;
5466 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, DDBLT_COLORFILL
, &BltFx
);
5469 /* rendertarget and deptth stencil functions */
5470 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5471 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5473 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5474 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5475 return WINED3DERR_INVALIDCALL
;
5478 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5479 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5480 /* Note inc ref on returned surface */
5481 if(*ppRenderTarget
!= NULL
)
5482 IWineD3DSurface_AddRef(*ppRenderTarget
);
5486 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
5487 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5488 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5489 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5490 IWineD3DSwapChainImpl
*Swapchain
;
5493 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
5495 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5496 if(hr
!= WINED3D_OK
) {
5497 ERR("Can't get the swapchain\n");
5501 /* Make sure to release the swapchain */
5502 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5504 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5505 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5506 return WINED3DERR_INVALIDCALL
;
5508 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5509 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5510 return WINED3DERR_INVALIDCALL
;
5513 if(Swapchain
->frontBuffer
!= Front
) {
5514 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5516 if(Swapchain
->frontBuffer
)
5517 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5518 Swapchain
->frontBuffer
= Front
;
5520 if(Swapchain
->frontBuffer
) {
5521 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5525 if(Back
&& !Swapchain
->backBuffer
) {
5526 /* We need memory for the back buffer array - only one back buffer this way */
5527 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
5528 if(!Swapchain
->backBuffer
) {
5529 ERR("Out of memory\n");
5530 return E_OUTOFMEMORY
;
5534 if(Swapchain
->backBuffer
[0] != Back
) {
5535 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
5537 if(!Swapchain
->backBuffer
[0]) {
5538 /* GL was told to draw to the front buffer at creation,
5541 glDrawBuffer(GL_BACK
);
5542 checkGLcall("glDrawBuffer(GL_BACK)");
5543 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5544 Swapchain
->presentParms
.BackBufferCount
= 1;
5546 /* That makes problems - disable for now */
5547 /* glDrawBuffer(GL_FRONT); */
5548 checkGLcall("glDrawBuffer(GL_FRONT)");
5549 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5550 Swapchain
->presentParms
.BackBufferCount
= 0;
5554 if(Swapchain
->backBuffer
[0])
5555 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5556 Swapchain
->backBuffer
[0] = Back
;
5558 if(Swapchain
->backBuffer
[0]) {
5559 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
5561 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
5569 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
5570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5571 *ppZStencilSurface
= This
->depthStencilBuffer
;
5572 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
5574 if(*ppZStencilSurface
!= NULL
) {
5575 /* Note inc ref on returned surface */
5576 IWineD3DSurface_AddRef(*ppZStencilSurface
);
5581 static void bind_fbo(IWineD3DDevice
*iface
) {
5582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5585 GL_EXTCALL(glGenFramebuffersEXT(1, &This
->fbo
));
5586 checkGLcall("glGenFramebuffersEXT()");
5588 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, This
->fbo
));
5589 checkGLcall("glBindFramebuffer()");
5592 /* TODO: Handle stencil attachments */
5593 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
5594 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5595 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
5597 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
5601 if (depth_stencil_impl
) {
5602 GLenum texttarget
, target
;
5603 GLint old_binding
= 0;
5605 IWineD3DSurface_PreLoad(depth_stencil
);
5606 texttarget
= depth_stencil_impl
->glDescription
.target
;
5607 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5609 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5610 glBindTexture(target
, depth_stencil_impl
->glDescription
.textureName
);
5611 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5612 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5613 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5614 glBindTexture(target
, old_binding
);
5616 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
, depth_stencil_impl
->glDescription
.textureName
, 0));
5617 checkGLcall("glFramebufferTexture2DEXT()");
5619 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
5620 checkGLcall("glFramebufferTexture2DEXT()");
5623 if (!This
->render_offscreen
) {
5624 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5625 checkGLcall("glBindFramebuffer()");
5629 static void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
5630 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5631 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
5633 if (idx
>= GL_LIMITS(buffers
)) {
5634 ERR("%p : Trying to set render target %d, but only %d supported\n", This
, idx
, GL_LIMITS(buffers
));
5640 GLenum texttarget
, target
;
5641 GLint old_binding
= 0;
5643 IWineD3DSurface_PreLoad(render_target
);
5644 texttarget
= rtimpl
->glDescription
.target
;
5645 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5647 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5648 glBindTexture(target
, rtimpl
->glDescription
.textureName
);
5649 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
5650 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
5651 glBindTexture(target
, old_binding
);
5653 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
, rtimpl
->glDescription
.textureName
, 0));
5654 checkGLcall("glFramebufferTexture2DEXT()");
5656 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
5658 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
5659 checkGLcall("glFramebufferTexture2DEXT()");
5661 This
->draw_buffers
[idx
] = GL_NONE
;
5664 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
5665 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
5666 checkGLcall("glDrawBuffers()");
5669 if (!This
->render_offscreen
) {
5670 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5671 checkGLcall("glBindFramebuffer()");
5675 /* internal static helper functions */
5676 static HRESULT WINAPI
IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice
* iface
,
5677 IWineD3DSurface
*RenderSurface
);
5679 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
5680 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5681 HRESULT hr
= WINED3D_OK
;
5682 WINED3DVIEWPORT viewport
;
5684 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5686 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5687 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5688 return WINED3DERR_INVALIDCALL
;
5691 /* MSDN says that null disables the render target
5692 but a device must always be associated with a render target
5693 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5695 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5698 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5699 FIXME("Trying to set render target 0 to NULL\n");
5700 return WINED3DERR_INVALIDCALL
;
5702 /* TODO: replace Impl* usage with interface usage */
5703 if (pRenderTarget
&& !((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
5704 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
);
5705 return WINED3DERR_INVALIDCALL
;
5707 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5708 * builds, but I think wine counts as a 'debug' build for now.
5709 ******************************/
5710 /* If we are trying to set what we already have, don't bother */
5711 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5712 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5714 /* Otherwise, set the render target up */
5716 if (!This
->sceneEnded
) {
5717 IWineD3DDevice_EndScene(iface
);
5719 TRACE("clearing renderer\n");
5720 /* IWineD3DDeviceImpl_CleanRender(iface); */
5721 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5722 depending on the renter target implementation being used.
5723 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5724 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5725 stencil buffer and incure an extra memory overhead */
5726 if (RenderTargetIndex
== 0) {
5727 hr
= IWineD3DDeviceImpl_ActiveRender(iface
, pRenderTarget
);
5732 /* Replace the render target */
5733 if (This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5734 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5735 if (pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5737 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5738 set_render_target_fbo(iface
, RenderTargetIndex
, pRenderTarget
);
5742 if (SUCCEEDED(hr
)) {
5743 /* Finally, reset the viewport as the MSDN states. */
5744 /* TODO: Replace impl usage */
5745 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5746 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5749 viewport
.MaxZ
= 1.0f
;
5750 viewport
.MinZ
= 0.0f
;
5751 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
5753 FIXME("Unknown error setting the render target\n");
5755 This
->sceneEnded
= FALSE
;
5759 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5760 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5761 HRESULT hr
= WINED3D_OK
;
5762 IWineD3DSurface
*tmp
;
5764 TRACE("(%p) Swapping z-buffer\n",This
);
5766 if (pNewZStencil
== This
->stencilBufferTarget
) {
5767 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5769 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5770 * depending on the renter target implementation being used.
5771 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5772 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5773 * stencil buffer and incure an extra memory overhead
5774 ******************************************************/
5777 tmp
= This
->stencilBufferTarget
;
5778 This
->stencilBufferTarget
= pNewZStencil
;
5779 /* should we be calling the parent or the wined3d surface? */
5780 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5781 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5783 /** TODO: glEnable/glDisable on depth/stencil depending on
5784 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5785 **********************************************************/
5786 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5787 set_depth_stencil_fbo(iface
, pNewZStencil
);
5795 #ifdef GL_VERSION_1_3
5796 /* Internal functions not in DirectX */
5797 /** TODO: move this off to the opengl context manager
5798 *(the swapchain doesn't need to know anything about offscreen rendering!)
5799 ****************************************************/
5801 static HRESULT WINAPI
IWineD3DDeviceImpl_CleanRender(IWineD3DDevice
* iface
, IWineD3DSwapChainImpl
*swapchain
)
5803 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5805 TRACE("(%p), %p\n", This
, swapchain
);
5807 if (swapchain
->win
!= swapchain
->drawable
) {
5808 /* Set everything back the way it ws */
5809 swapchain
->render_ctx
= swapchain
->glCtx
;
5810 swapchain
->drawable
= swapchain
->win
;
5815 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5816 static HRESULT WINAPI
IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, glContext
**context
) {
5817 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5820 unsigned int height
;
5821 WINED3DFORMAT format
;
5822 WINED3DSURFACE_DESC surfaceDesc
;
5823 memset(&surfaceDesc
, 0, sizeof(surfaceDesc
));
5824 surfaceDesc
.Width
= &width
;
5825 surfaceDesc
.Height
= &height
;
5826 surfaceDesc
.Format
= &format
;
5827 IWineD3DSurface_GetDesc(pSurface
, &surfaceDesc
);
5829 /* I need a get width/height function (and should do something with the format) */
5830 for (i
= 0; i
< CONTEXT_CACHE
; ++i
) {
5831 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5832 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5833 the pSurface can be set to 0 allowing it to be reused from cache **/
5834 if (This
->contextCache
[i
].Width
== width
&& This
->contextCache
[i
].Height
== height
5835 && (!pbuffer_per_surface
|| This
->contextCache
[i
].pSurface
== pSurface
|| This
->contextCache
[i
].pSurface
== NULL
)) {
5836 *context
= &This
->contextCache
[i
];
5839 if (This
->contextCache
[i
].Width
== 0) {
5840 This
->contextCache
[i
].pSurface
= pSurface
;
5841 This
->contextCache
[i
].Width
= width
;
5842 This
->contextCache
[i
].Height
= height
;
5843 *context
= &This
->contextCache
[i
];
5847 if (i
== CONTEXT_CACHE
) {
5848 int minUsage
= 0x7FFFFFFF; /* MAX_INT */
5849 glContext
*dropContext
= 0;
5850 for (i
= 0; i
< CONTEXT_CACHE
; i
++) {
5851 if (This
->contextCache
[i
].usedcount
< minUsage
) {
5852 dropContext
= &This
->contextCache
[i
];
5853 minUsage
= This
->contextCache
[i
].usedcount
;
5856 /* clean up the context (this doesn't work for ATI at the moment */
5858 glXDestroyContext(swapchain
->display
, dropContext
->context
);
5859 glXDestroyPbuffer(swapchain
->display
, dropContext
->drawable
);
5862 dropContext
->Width
= 0;
5863 dropContext
->pSurface
= pSurface
;
5864 *context
= dropContext
;
5866 if (++This
->contextCache
[i
].usedcount
== 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5867 for (i
= 0; i
< CONTEXT_CACHE
; i
++) {
5868 This
->contextCache
[i
].usedcount
= max(0, This
->contextCache
[i
].usedcount
- (0x7FFFFFFF /* MAX_INT */ >> 1));
5872 if (*context
!= NULL
)
5875 return E_OUTOFMEMORY
;
5879 /* Reapply the device stateblock */
5880 static void device_reapply_stateblock(IWineD3DDeviceImpl
* This
) {
5883 IWineD3DStateBlockImpl
*oldUpdateStateBlock
;
5886 /* Disable recording */
5887 oldUpdateStateBlock
= This
->updateStateBlock
;
5888 oldRecording
= This
->isRecordingState
;
5889 This
->isRecordingState
= FALSE
;
5890 This
->updateStateBlock
= This
->stateBlock
;
5892 /* Reapply the state block */
5893 IWineD3DStateBlock_Apply((IWineD3DStateBlock
*)This
->stateBlock
);
5895 /* Temporaryily mark all render states dirty to force reapplication
5896 * until the context management for is integrated with the state management
5897 * The same for the pixel shader, vertex declaration and vertex shader
5898 * Sampler states and texture stage states are marked
5899 * dirty my StateBlock::Apply already.
5901 for(i
= 1; i
< WINEHIGHEST_RENDER_STATE
; i
++) {
5902 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(i
));
5904 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
5905 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5906 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
5908 /* Restore recording */
5909 This
->isRecordingState
= oldRecording
;
5910 This
->updateStateBlock
= oldUpdateStateBlock
;
5913 /* Set offscreen rendering. When rendering offscreen the surface will be
5914 * rendered upside down to compensate for the fact that D3D texture coordinates
5915 * are flipped compared to GL texture coordinates. The cullmode is affected by
5916 * this, so it must be updated. To update the cullmode stateblock recording has
5917 * to be temporarily disabled. The new state management code will hopefully
5918 * make this unnecessary */
5919 static void device_render_to_texture(IWineD3DDeviceImpl
* This
, BOOL isTexture
) {
5922 IWineD3DStateBlockImpl
*oldUpdateStateBlock
;
5924 /* Nothing to update, return. */
5925 if (This
->render_offscreen
== isTexture
) return;
5927 /* Disable recording */
5928 oldUpdateStateBlock
= This
->updateStateBlock
;
5929 oldRecording
= This
->isRecordingState
;
5930 This
->isRecordingState
= FALSE
;
5931 This
->updateStateBlock
= This
->stateBlock
;
5933 This
->render_offscreen
= isTexture
;
5934 if (This
->depth_copy_state
!= WINED3D_DCS_NO_COPY
) {
5935 This
->depth_copy_state
= WINED3D_DCS_COPY
;
5937 This
->last_was_rhw
= FALSE
;
5938 /* Viewport state will reapply the projection matrix for now */
5939 IWineD3DDeviceImpl_MarkStateDirty(This
, WINED3DRS_CULLMODE
);
5941 /* Restore recording */
5942 This
->isRecordingState
= oldRecording
;
5943 This
->updateStateBlock
= oldUpdateStateBlock
;
5946 /* Returns an array of compatible FBconfig(s).
5947 * The array must be freed with XFree. Requires ENTER_GL() */
5949 static GLXFBConfig
* device_find_fbconfigs(
5950 IWineD3DDeviceImpl
* This
,
5951 IWineD3DSwapChainImpl
* implicitSwapchainImpl
,
5952 IWineD3DSurface
* RenderSurface
) {
5954 GLXFBConfig
* cfgs
= NULL
;
5959 IWineD3DSurface
*StencilSurface
= This
->stencilBufferTarget
;
5960 WINED3DFORMAT BackBufferFormat
= ((IWineD3DSurfaceImpl
*) RenderSurface
)->resource
.format
;
5961 WINED3DFORMAT StencilBufferFormat
= (NULL
!= StencilSurface
) ? ((IWineD3DSurfaceImpl
*) StencilSurface
)->resource
.format
: 0;
5964 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5965 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5968 #define PUSH1(att) attribs[nAttribs++] = (att);
5969 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5971 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
5973 PUSH2(GLX_DRAWABLE_TYPE
, GLX_PBUFFER_BIT
);
5974 PUSH2(GLX_X_RENDERABLE
, TRUE
);
5975 PUSH2(GLX_DOUBLEBUFFER
, TRUE
);
5976 TRACE("calling makeglcfg\n");
5977 D3DFmtMakeGlCfg(BackBufferFormat
, StencilBufferFormat
, attribs
, &nAttribs
, FALSE
/* alternate */);
5979 TRACE("calling chooseFGConfig\n");
5980 cfgs
= glXChooseFBConfig(implicitSwapchainImpl
->display
,
5981 DefaultScreen(implicitSwapchainImpl
->display
),
5984 /* OK we didn't find the exact config, so use any reasonable match */
5985 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
5987 static BOOL show_message
= TRUE
;
5989 ERR("Failed to find exact match, finding alternative but you may "
5990 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
5991 show_message
= FALSE
;
5994 PUSH2(GLX_DRAWABLE_TYPE
, GLX_PBUFFER_BIT
| GLX_WINDOW_BIT
);
5995 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
5996 PUSH2(GLX_RENDER_TYPE
, GLX_RGBA_BIT
);
5997 PUSH2(GLX_DOUBLEBUFFER
, FALSE
);
5998 TRACE("calling makeglcfg\n");
5999 D3DFmtMakeGlCfg(BackBufferFormat
, StencilBufferFormat
, attribs
, &nAttribs
, TRUE
/* alternate */);
6001 cfgs
= glXChooseFBConfig(implicitSwapchainImpl
->display
,
6002 DefaultScreen(implicitSwapchainImpl
->display
),
6007 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
6008 BackBufferFormat
, debug_d3dformat(BackBufferFormat
),
6009 StencilBufferFormat
, debug_d3dformat(StencilBufferFormat
));
6013 for (i
= 0; i
< nCfgs
; ++i
) {
6014 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat
,
6015 debug_d3dformat(BackBufferFormat
), StencilBufferFormat
,
6016 debug_d3dformat(StencilBufferFormat
), i
, cfgs
[i
]);
6018 if (NULL
!= This
->renderTarget
) {
6020 vcheckGLcall("glFlush");
6021 /** This is only useful if the old render target was a swapchain,
6022 * we need to supercede this with a function that displays
6023 * the current buffer on the screen. This is easy to do in glx1.3 but
6024 * we need to do copy-write pixels in glx 1.2.
6025 ************************************************/
6026 glXSwapBuffers(implicitSwapChainImpl
->display
,
6027 implicitSwapChainImpl
->drawable
);
6028 printf("Hit Enter to get next frame ...\n");
6039 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6040 * the functionality needs splitting up so that we don't do more than we should do.
6041 * this only seems to impact performance a little.
6042 ******************************/
6043 static HRESULT WINAPI
IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice
* iface
,
6044 IWineD3DSurface
*RenderSurface
) {
6047 * Currently only active for GLX >= 1.3
6048 * for others versions we'll have to use GLXPixmaps
6050 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6051 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6052 * so only check OpenGL version
6053 * ..........................
6054 * I don't believe that it is a problem with NVidia headers,
6055 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6056 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6058 * Your application will report GLX version 1.2 on glXQueryVersion.
6059 * However, it is safe to call the GLX 1.3 functions as described below.
6061 #if defined(GL_VERSION_1_3)
6063 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6064 GLXFBConfig
* cfgs
= NULL
;
6065 IWineD3DSwapChain
*currentSwapchain
;
6066 IWineD3DSwapChainImpl
*currentSwapchainImpl
;
6067 IWineD3DSwapChain
*implicitSwapchain
;
6068 IWineD3DSwapChainImpl
*implicitSwapchainImpl
;
6069 IWineD3DSwapChain
*renderSurfaceSwapchain
;
6070 IWineD3DSwapChainImpl
*renderSurfaceSwapchainImpl
;
6072 /* Obtain a reference to the device implicit swapchain,
6073 * the swapchain of the current render target,
6074 * and the swapchain of the new render target.
6075 * Fallback to device implicit swapchain if the current render target doesn't have one */
6076 IWineD3DDevice_GetSwapChain(iface
, 0, &implicitSwapchain
);
6077 IWineD3DSurface_GetContainer(RenderSurface
, &IID_IWineD3DSwapChain
, (void**) &renderSurfaceSwapchain
);
6078 IWineD3DSurface_GetContainer(This
->render_targets
[0], &IID_IWineD3DSwapChain
, (void **)¤tSwapchain
);
6079 if (currentSwapchain
== NULL
)
6080 IWineD3DDevice_GetSwapChain(iface
, 0, ¤tSwapchain
);
6082 currentSwapchainImpl
= (IWineD3DSwapChainImpl
*) currentSwapchain
;
6083 implicitSwapchainImpl
= (IWineD3DSwapChainImpl
*) implicitSwapchain
;
6084 renderSurfaceSwapchainImpl
= (IWineD3DSwapChainImpl
*) renderSurfaceSwapchain
;
6089 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6090 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6091 **********************************************************************/
6092 if (renderSurfaceSwapchain
!= NULL
) {
6094 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6095 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6096 TRACE("making swapchain active\n");
6097 if (RenderSurface
!= This
->render_targets
[0]) {
6098 BOOL backbuf
= FALSE
;
6101 for(i
= 0; i
< renderSurfaceSwapchainImpl
->presentParms
.BackBufferCount
; i
++) {
6102 if(RenderSurface
== renderSurfaceSwapchainImpl
->backBuffer
[i
]) {
6110 /* This could be flagged so that some operations work directly with the front buffer */
6111 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6113 if (glXMakeCurrent(renderSurfaceSwapchainImpl
->display
,
6114 renderSurfaceSwapchainImpl
->win
,
6115 renderSurfaceSwapchainImpl
->glCtx
) == False
) {
6117 TRACE("Error in setting current context: context %p drawable %ld !\n",
6118 implicitSwapchainImpl
->glCtx
, implicitSwapchainImpl
->win
);
6120 checkGLcall("glXMakeContextCurrent");
6122 /* Clean up the old context */
6123 IWineD3DDeviceImpl_CleanRender(iface
, currentSwapchainImpl
);
6125 /* Reapply the stateblock, and set the device not to render to texture */
6126 device_reapply_stateblock(This
);
6127 device_render_to_texture(This
, FALSE
);
6130 /* Offscreen rendering: PBuffers (currently disabled).
6131 * Also note that this path is never reached if FBOs are supported */
6132 } else if (wined3d_settings
.offscreen_rendering_mode
== ORM_PBUFFER
&&
6133 (cfgs
= device_find_fbconfigs(This
, implicitSwapchainImpl
, RenderSurface
)) != NULL
) {
6135 /** ********************************************************************
6136 * This is a quickly hacked out implementation of offscreen textures.
6137 * It will work in most cases but there may be problems if the client
6138 * modifies the texture directly, or expects the contents of the rendertarget
6141 * There are some real speed vs compatibility issues here:
6142 * we should really use a new context for every texture, but that eats ram.
6143 * we should also be restoring the texture to the pbuffer but that eats CPU
6144 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6145 * but if this means reusing the display backbuffer then we need to make sure that
6146 * states are correctly preserved.
6147 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6148 * and gain a good performance increase at the cost of compatibility.
6149 * I would suggest that, when this is the case, a user configurable flag be made
6150 * available, allowing the user to choose the best emulated experience for them.
6151 *********************************************************************/
6153 XVisualInfo
*visinfo
;
6154 glContext
*newContext
;
6156 /* Here were using a shared context model */
6157 if (WINED3D_OK
!= IWineD3DDeviceImpl_FindGLContext(iface
, RenderSurface
, &newContext
)) {
6158 FIXME("(%p) : Failed to find a context for surface %p\n", iface
, RenderSurface
);
6161 /* If the context doesn't exist then create a new one */
6162 /* TODO: This should really be part of findGlContext */
6163 if (NULL
== newContext
->context
) {
6168 TRACE("making new buffer\n");
6169 attribs
[nAttribs
++] = GLX_PBUFFER_WIDTH
;
6170 attribs
[nAttribs
++] = newContext
->Width
;
6171 attribs
[nAttribs
++] = GLX_PBUFFER_HEIGHT
;
6172 attribs
[nAttribs
++] = newContext
->Height
;
6173 attribs
[nAttribs
++] = None
;
6175 newContext
->drawable
= glXCreatePbuffer(implicitSwapchainImpl
->display
, cfgs
[0], attribs
);
6177 /** ****************************************
6178 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6180 * In future releases, we may provide the calls glXCreateNewContext,
6181 * glXQueryDrawable and glXMakeContextCurrent.
6182 * so until then we have to use glXGetVisualFromFBConfig &co..
6183 ********************************************/
6185 visinfo
= glXGetVisualFromFBConfig(implicitSwapchainImpl
->display
, cfgs
[0]);
6187 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6189 newContext
->context
= glXCreateContext(
6190 implicitSwapchainImpl
->display
, visinfo
,
6191 implicitSwapchainImpl
->glCtx
, GL_TRUE
);
6196 if (NULL
== newContext
|| NULL
== newContext
->context
) {
6197 ERR("(%p) : Failed to find a context for surface %p\n", iface
, RenderSurface
);
6199 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6200 if (glXMakeCurrent(implicitSwapchainImpl
->display
,
6201 newContext
->drawable
, newContext
->context
) == False
) {
6203 TRACE("Error in setting current context: context %p drawable %ld\n",
6204 newContext
->context
, newContext
->drawable
);
6206 checkGLcall("glXMakeContextCurrent");
6208 /* Clean up the old context */
6209 IWineD3DDeviceImpl_CleanRender(iface
, currentSwapchainImpl
);
6211 /* Reapply stateblock, and set device to render to a texture */
6212 device_reapply_stateblock(This
);
6213 device_render_to_texture(This
, TRUE
);
6215 /* Set the current context of the swapchain to the new context */
6216 implicitSwapchainImpl
->drawable
= newContext
->drawable
;
6217 implicitSwapchainImpl
->render_ctx
= newContext
->context
;
6220 /* Same context, but update render_offscreen and cull mode */
6221 device_render_to_texture(This
, TRUE
);
6224 if (cfgs
!= NULL
) XFree(cfgs
);
6225 if (implicitSwapchain
!= NULL
) IWineD3DSwapChain_Release(implicitSwapchain
);
6226 if (currentSwapchain
!= NULL
) IWineD3DSwapChain_Release(currentSwapchain
);
6227 if (renderSurfaceSwapchain
!= NULL
) IWineD3DSwapChain_Release(renderSurfaceSwapchain
);
6233 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6234 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6235 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6236 /* TODO: the use of Impl is deprecated. */
6237 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6239 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6241 /* some basic validation checks */
6242 if(This
->cursorTexture
) {
6244 glDeleteTextures(1, &This
->cursorTexture
);
6246 This
->cursorTexture
= 0;
6250 /* MSDN: Cursor must be A8R8G8B8 */
6251 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
6252 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6253 return WINED3DERR_INVALIDCALL
;
6256 /* MSDN: Cursor must be smaller than the display mode */
6257 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6258 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6259 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
);
6260 return WINED3DERR_INVALIDCALL
;
6263 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6264 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6265 * Texture and Blitting code to draw the cursor
6267 pSur
->Flags
|= SFLAG_FORCELOAD
;
6268 IWineD3DSurface_PreLoad(pCursorBitmap
);
6269 pSur
->Flags
&= ~SFLAG_FORCELOAD
;
6270 /* Do not store the surface's pointer because the application may release
6271 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6272 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6274 This
->cursorTexture
= pSur
->glDescription
.textureName
;
6275 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6276 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6277 pSur
->glDescription
.textureName
= 0; /* Prevent the texture from being changed or deleted */
6280 This
->xHotSpot
= XHotSpot
;
6281 This
->yHotSpot
= YHotSpot
;
6285 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6286 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6287 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6289 This
->xScreenSpace
= XScreenSpace
;
6290 This
->yScreenSpace
= YScreenSpace
;
6296 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6297 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6298 BOOL oldVisible
= This
->bCursorVisible
;
6299 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6301 if(This
->cursorTexture
)
6302 This
->bCursorVisible
= bShow
;
6307 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
6308 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6309 TRACE("(%p) : state (%u)\n", This
, This
->state
);
6310 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6311 switch (This
->state
) {
6314 case WINED3DERR_DEVICELOST
:
6316 ResourceList
*resourceList
= This
->resources
;
6317 while (NULL
!= resourceList
) {
6318 if (((IWineD3DResourceImpl
*)resourceList
->resource
)->resource
.pool
== WINED3DPOOL_DEFAULT
/* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6319 return WINED3DERR_DEVICENOTRESET
;
6320 resourceList
= resourceList
->next
;
6322 return WINED3DERR_DEVICELOST
;
6324 case WINED3DERR_DRIVERINTERNALERROR
:
6325 return WINED3DERR_DRIVERINTERNALERROR
;
6329 return WINED3DERR_DRIVERINTERNALERROR
;
6333 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6334 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6335 /** FIXME: Resource tracking needs to be done,
6336 * The closes we can do to this is set the priorities of all managed textures low
6337 * and then reset them.
6338 ***********************************************************/
6339 FIXME("(%p) : stub\n", This
);
6343 void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6344 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6345 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6346 /* Release the DC */
6347 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6348 DeleteDC(surface
->hDC
);
6349 /* Release the DIB section */
6350 DeleteObject(surface
->dib
.DIBsection
);
6351 surface
->dib
.bitmap_data
= NULL
;
6352 surface
->resource
.allocatedMemory
= NULL
;
6353 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6355 surface
->currentDesc
.Width
= *pPresentationParameters
->BackBufferWidth
;
6356 surface
->currentDesc
.Height
= *pPresentationParameters
->BackBufferHeight
;
6357 if (wined3d_settings
.nonpower2_mode
== NP2_NATIVE
) {
6358 surface
->pow2Width
= *pPresentationParameters
->BackBufferWidth
;
6359 surface
->pow2Height
= *pPresentationParameters
->BackBufferHeight
;
6361 surface
->pow2Width
= surface
->pow2Height
= 1;
6362 while (surface
->pow2Width
< *pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6363 while (surface
->pow2Height
< *pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6365 if(surface
->glDescription
.textureName
) {
6367 glDeleteTextures(1, &surface
->glDescription
.textureName
);
6369 surface
->glDescription
.textureName
= 0;
6371 if(surface
->pow2Width
!= *pPresentationParameters
->BackBufferWidth
||
6372 surface
->pow2Height
!= *pPresentationParameters
->BackBufferHeight
) {
6373 surface
->Flags
|= SFLAG_NONPOW2
;
6375 surface
->Flags
&= ~SFLAG_NONPOW2
;
6377 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
6378 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6381 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6382 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6383 IWineD3DSwapChainImpl
*swapchain
;
6385 BOOL DisplayModeChanged
= FALSE
;
6386 WINED3DDISPLAYMODE mode
;
6387 TRACE("(%p)\n", This
);
6389 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6391 ERR("Failed to get the first implicit swapchain\n");
6395 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6396 * on an existing gl context, so there's no real need for recreation.
6398 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6400 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6402 TRACE("New params:\n");
6403 TRACE("BackBufferWidth = %d\n", *pPresentationParameters
->BackBufferWidth
);
6404 TRACE("BackBufferHeight = %d\n", *pPresentationParameters
->BackBufferHeight
);
6405 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters
->BackBufferFormat
));
6406 TRACE("BackBufferCount = %d\n", *pPresentationParameters
->BackBufferCount
);
6407 TRACE("MultiSampleType = %d\n", *pPresentationParameters
->MultiSampleType
);
6408 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters
->MultiSampleQuality
);
6409 TRACE("SwapEffect = %d\n", *pPresentationParameters
->SwapEffect
);
6410 TRACE("hDeviceWindow = %p\n", *pPresentationParameters
->hDeviceWindow
);
6411 TRACE("Windowed = %s\n", *pPresentationParameters
->Windowed
? "true" : "false");
6412 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6413 TRACE("Flags = %08x\n", *pPresentationParameters
->Flags
);
6414 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters
->FullScreen_RefreshRateInHz
);
6415 TRACE("PresentationInterval = %d\n", *pPresentationParameters
->PresentationInterval
);
6417 /* No special treatment of these parameters. Just store them */
6418 swapchain
->presentParms
.SwapEffect
= *pPresentationParameters
->SwapEffect
;
6419 swapchain
->presentParms
.Flags
= *pPresentationParameters
->Flags
;
6420 swapchain
->presentParms
.PresentationInterval
= *pPresentationParameters
->PresentationInterval
;
6421 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= *pPresentationParameters
->FullScreen_RefreshRateInHz
;
6423 /* What to do about these? */
6424 if(*pPresentationParameters
->BackBufferCount
!= 0 &&
6425 *pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6426 ERR("Cannot change the back buffer count yet\n");
6428 if(*pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6429 *pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6430 ERR("Cannot change the back buffer format yet\n");
6432 if(*pPresentationParameters
->hDeviceWindow
!= NULL
&&
6433 *pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6434 ERR("Cannot change the device window yet\n");
6436 if(*pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
6437 ERR("What do do about a changed auto depth stencil parameter?\n");
6440 if(*pPresentationParameters
->Windowed
) {
6441 mode
.Width
= swapchain
->orig_width
;
6442 mode
.Height
= swapchain
->orig_height
;
6443 mode
.RefreshRate
= 0;
6444 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6446 mode
.Width
= *pPresentationParameters
->BackBufferWidth
;
6447 mode
.Height
= *pPresentationParameters
->BackBufferHeight
;
6448 mode
.RefreshRate
= *pPresentationParameters
->FullScreen_RefreshRateInHz
;
6449 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6452 /* Should Width == 800 && Height == 0 set 800x600? */
6453 if(*pPresentationParameters
->BackBufferWidth
!= 0 && *pPresentationParameters
->BackBufferHeight
!= 0 &&
6454 (*pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6455 *pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6462 vp
.Width
= *pPresentationParameters
->BackBufferWidth
;
6463 vp
.Height
= *pPresentationParameters
->BackBufferHeight
;
6467 if(!*pPresentationParameters
->Windowed
) {
6468 DisplayModeChanged
= TRUE
;
6470 swapchain
->presentParms
.BackBufferWidth
= *pPresentationParameters
->BackBufferWidth
;
6471 swapchain
->presentParms
.BackBufferHeight
= *pPresentationParameters
->BackBufferHeight
;
6473 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6474 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6475 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6478 /* Now set the new viewport */
6479 IWineD3DDevice_SetViewport(iface
, &vp
);
6482 if((*pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6483 (swapchain
->presentParms
.Windowed
&& !*pPresentationParameters
->Windowed
) ||
6484 DisplayModeChanged
) {
6485 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6488 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6492 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6493 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6494 /** FIXME: always true at the moment **/
6495 if(!bEnableDialogs
) {
6496 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6502 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6503 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6504 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6506 *pParameters
= This
->createParms
;
6510 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6511 IWineD3DSwapChain
*swapchain
;
6512 HRESULT hrc
= WINED3D_OK
;
6514 TRACE("Relaying to swapchain\n");
6516 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6517 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
6518 IWineD3DSwapChain_Release(swapchain
);
6523 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6524 IWineD3DSwapChain
*swapchain
;
6525 HRESULT hrc
= WINED3D_OK
;
6527 TRACE("Relaying to swapchain\n");
6529 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
6530 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6531 IWineD3DSwapChain_Release(swapchain
);
6537 /** ********************************************************
6538 * Notification functions
6539 ** ********************************************************/
6540 /** This function must be called in the release of a resource when ref == 0,
6541 * the contents of resource must still be correct,
6542 * any handels to other resource held by the caller must be closed
6543 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6544 *****************************************************/
6545 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6546 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6547 ResourceList
* resourceList
;
6549 TRACE("(%p) : resource %p\n", This
, resource
);
6551 EnterCriticalSection(&resourceStoreCriticalSection
);
6553 /* add a new texture to the frot of the linked list */
6554 resourceList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ResourceList
));
6555 resourceList
->resource
= resource
;
6557 /* Get the old head */
6558 resourceList
->next
= This
->resources
;
6560 This
->resources
= resourceList
;
6561 TRACE("Added resource %p with element %p pointing to %p\n", resource
, resourceList
, resourceList
->next
);
6564 LeaveCriticalSection(&resourceStoreCriticalSection
);
6569 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6571 ResourceList
* resourceList
= NULL
;
6572 ResourceList
* previousResourceList
= NULL
;
6574 TRACE("(%p) : resource %p\n", This
, resource
);
6577 EnterCriticalSection(&resourceStoreCriticalSection
);
6579 resourceList
= This
->resources
;
6581 while (resourceList
!= NULL
) {
6582 if(resourceList
->resource
== resource
) break;
6583 previousResourceList
= resourceList
;
6584 resourceList
= resourceList
->next
;
6587 if (resourceList
== NULL
) {
6588 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource
);
6590 LeaveCriticalSection(&resourceStoreCriticalSection
);
6594 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList
->resource
, resourceList
, resourceList
->next
, previousResourceList
);
6596 /* make sure we don't leave a hole in the list */
6597 if (previousResourceList
!= NULL
) {
6598 previousResourceList
->next
= resourceList
->next
;
6600 This
->resources
= resourceList
->next
;
6604 LeaveCriticalSection(&resourceStoreCriticalSection
);
6610 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
6611 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6614 TRACE("(%p) : resource %p\n", This
, resource
);
6615 switch(IWineD3DResource_GetType(resource
)){
6616 case WINED3DRTYPE_SURFACE
:
6617 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6619 case WINED3DRTYPE_TEXTURE
:
6620 case WINED3DRTYPE_CUBETEXTURE
:
6621 case WINED3DRTYPE_VOLUMETEXTURE
:
6622 for (counter
= 0; counter
< GL_LIMITS(sampler_stages
); counter
++) {
6623 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6624 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6625 This
->stateBlock
->textures
[counter
] = NULL
;
6627 if (This
->updateStateBlock
!= This
->stateBlock
){
6628 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6629 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6630 This
->updateStateBlock
->textures
[counter
] = NULL
;
6635 case WINED3DRTYPE_VOLUME
:
6636 /* TODO: nothing really? */
6638 case WINED3DRTYPE_VERTEXBUFFER
:
6639 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6642 TRACE("Cleaning up stream pointers\n");
6644 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6645 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6646 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6648 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6649 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6650 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6651 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6652 /* Set changed flag? */
6655 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) */
6656 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6657 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6658 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6661 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6662 else { /* This shouldn't happen */
6663 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6670 case WINED3DRTYPE_INDEXBUFFER
:
6671 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6672 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6673 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
6674 This
->updateStateBlock
->pIndexData
= NULL
;
6677 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6678 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
6679 This
->stateBlock
->pIndexData
= NULL
;
6685 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
6690 /* Remove the resoruce from the resourceStore */
6691 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
6693 TRACE("Resource released\n");
6697 /**********************************************************
6698 * IWineD3DDevice VTbl follows
6699 **********************************************************/
6701 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
6703 /*** IUnknown methods ***/
6704 IWineD3DDeviceImpl_QueryInterface
,
6705 IWineD3DDeviceImpl_AddRef
,
6706 IWineD3DDeviceImpl_Release
,
6707 /*** IWineD3DDevice methods ***/
6708 IWineD3DDeviceImpl_GetParent
,
6709 /*** Creation methods**/
6710 IWineD3DDeviceImpl_CreateVertexBuffer
,
6711 IWineD3DDeviceImpl_CreateIndexBuffer
,
6712 IWineD3DDeviceImpl_CreateStateBlock
,
6713 IWineD3DDeviceImpl_CreateSurface
,
6714 IWineD3DDeviceImpl_CreateTexture
,
6715 IWineD3DDeviceImpl_CreateVolumeTexture
,
6716 IWineD3DDeviceImpl_CreateVolume
,
6717 IWineD3DDeviceImpl_CreateCubeTexture
,
6718 IWineD3DDeviceImpl_CreateQuery
,
6719 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
6720 IWineD3DDeviceImpl_CreateVertexDeclaration
,
6721 IWineD3DDeviceImpl_CreateVertexShader
,
6722 IWineD3DDeviceImpl_CreatePixelShader
,
6723 IWineD3DDeviceImpl_CreatePalette
,
6724 /*** Odd functions **/
6725 IWineD3DDeviceImpl_Init3D
,
6726 IWineD3DDeviceImpl_Uninit3D
,
6727 IWineD3DDeviceImpl_SetFullscreen
,
6728 IWineD3DDeviceImpl_EnumDisplayModes
,
6729 IWineD3DDeviceImpl_EvictManagedResources
,
6730 IWineD3DDeviceImpl_GetAvailableTextureMem
,
6731 IWineD3DDeviceImpl_GetBackBuffer
,
6732 IWineD3DDeviceImpl_GetCreationParameters
,
6733 IWineD3DDeviceImpl_GetDeviceCaps
,
6734 IWineD3DDeviceImpl_GetDirect3D
,
6735 IWineD3DDeviceImpl_GetDisplayMode
,
6736 IWineD3DDeviceImpl_SetDisplayMode
,
6737 IWineD3DDeviceImpl_GetHWND
,
6738 IWineD3DDeviceImpl_SetHWND
,
6739 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
6740 IWineD3DDeviceImpl_GetRasterStatus
,
6741 IWineD3DDeviceImpl_GetSwapChain
,
6742 IWineD3DDeviceImpl_Reset
,
6743 IWineD3DDeviceImpl_SetDialogBoxMode
,
6744 IWineD3DDeviceImpl_SetCursorProperties
,
6745 IWineD3DDeviceImpl_SetCursorPosition
,
6746 IWineD3DDeviceImpl_ShowCursor
,
6747 IWineD3DDeviceImpl_TestCooperativeLevel
,
6748 /*** Getters and setters **/
6749 IWineD3DDeviceImpl_SetClipPlane
,
6750 IWineD3DDeviceImpl_GetClipPlane
,
6751 IWineD3DDeviceImpl_SetClipStatus
,
6752 IWineD3DDeviceImpl_GetClipStatus
,
6753 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
6754 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
6755 IWineD3DDeviceImpl_SetDepthStencilSurface
,
6756 IWineD3DDeviceImpl_GetDepthStencilSurface
,
6757 IWineD3DDeviceImpl_SetFVF
,
6758 IWineD3DDeviceImpl_GetFVF
,
6759 IWineD3DDeviceImpl_SetGammaRamp
,
6760 IWineD3DDeviceImpl_GetGammaRamp
,
6761 IWineD3DDeviceImpl_SetIndices
,
6762 IWineD3DDeviceImpl_GetIndices
,
6763 IWineD3DDeviceImpl_SetBasevertexIndex
,
6764 IWineD3DDeviceImpl_SetLight
,
6765 IWineD3DDeviceImpl_GetLight
,
6766 IWineD3DDeviceImpl_SetLightEnable
,
6767 IWineD3DDeviceImpl_GetLightEnable
,
6768 IWineD3DDeviceImpl_SetMaterial
,
6769 IWineD3DDeviceImpl_GetMaterial
,
6770 IWineD3DDeviceImpl_SetNPatchMode
,
6771 IWineD3DDeviceImpl_GetNPatchMode
,
6772 IWineD3DDeviceImpl_SetPaletteEntries
,
6773 IWineD3DDeviceImpl_GetPaletteEntries
,
6774 IWineD3DDeviceImpl_SetPixelShader
,
6775 IWineD3DDeviceImpl_GetPixelShader
,
6776 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
6777 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
6778 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
6779 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
6780 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
6781 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
6782 IWineD3DDeviceImpl_SetRenderState
,
6783 IWineD3DDeviceImpl_GetRenderState
,
6784 IWineD3DDeviceImpl_SetRenderTarget
,
6785 IWineD3DDeviceImpl_GetRenderTarget
,
6786 IWineD3DDeviceImpl_SetFrontBackBuffers
,
6787 IWineD3DDeviceImpl_SetSamplerState
,
6788 IWineD3DDeviceImpl_GetSamplerState
,
6789 IWineD3DDeviceImpl_SetScissorRect
,
6790 IWineD3DDeviceImpl_GetScissorRect
,
6791 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
6792 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
6793 IWineD3DDeviceImpl_SetStreamSource
,
6794 IWineD3DDeviceImpl_GetStreamSource
,
6795 IWineD3DDeviceImpl_SetStreamSourceFreq
,
6796 IWineD3DDeviceImpl_GetStreamSourceFreq
,
6797 IWineD3DDeviceImpl_SetTexture
,
6798 IWineD3DDeviceImpl_GetTexture
,
6799 IWineD3DDeviceImpl_SetTextureStageState
,
6800 IWineD3DDeviceImpl_GetTextureStageState
,
6801 IWineD3DDeviceImpl_SetTransform
,
6802 IWineD3DDeviceImpl_GetTransform
,
6803 IWineD3DDeviceImpl_SetVertexDeclaration
,
6804 IWineD3DDeviceImpl_GetVertexDeclaration
,
6805 IWineD3DDeviceImpl_SetVertexShader
,
6806 IWineD3DDeviceImpl_GetVertexShader
,
6807 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
6808 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
6809 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
6810 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
6811 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
6812 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
6813 IWineD3DDeviceImpl_SetViewport
,
6814 IWineD3DDeviceImpl_GetViewport
,
6815 IWineD3DDeviceImpl_MultiplyTransform
,
6816 IWineD3DDeviceImpl_ValidateDevice
,
6817 IWineD3DDeviceImpl_ProcessVertices
,
6818 /*** State block ***/
6819 IWineD3DDeviceImpl_BeginStateBlock
,
6820 IWineD3DDeviceImpl_EndStateBlock
,
6821 /*** Scene management ***/
6822 IWineD3DDeviceImpl_BeginScene
,
6823 IWineD3DDeviceImpl_EndScene
,
6824 IWineD3DDeviceImpl_Present
,
6825 IWineD3DDeviceImpl_Clear
,
6827 IWineD3DDeviceImpl_DrawPrimitive
,
6828 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
6829 IWineD3DDeviceImpl_DrawPrimitiveUP
,
6830 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
6831 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
6832 IWineD3DDeviceImpl_DrawRectPatch
,
6833 IWineD3DDeviceImpl_DrawTriPatch
,
6834 IWineD3DDeviceImpl_DeletePatch
,
6835 IWineD3DDeviceImpl_ColorFill
,
6836 IWineD3DDeviceImpl_UpdateTexture
,
6837 IWineD3DDeviceImpl_UpdateSurface
,
6838 IWineD3DDeviceImpl_GetRenderTargetData
,
6839 IWineD3DDeviceImpl_GetFrontBufferData
,
6840 IWineD3DDeviceImpl_SetupFullscreenWindow
,
6841 IWineD3DDeviceImpl_RestoreWindow
,
6842 /*** object tracking ***/
6843 IWineD3DDeviceImpl_ResourceReleased
6847 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
6848 WINED3DRS_ALPHABLENDENABLE
,
6849 WINED3DRS_ALPHAFUNC
,
6850 WINED3DRS_ALPHAREF
,
6851 WINED3DRS_ALPHATESTENABLE
,
6853 WINED3DRS_COLORWRITEENABLE
,
6854 WINED3DRS_DESTBLEND
,
6855 WINED3DRS_DITHERENABLE
,
6856 WINED3DRS_FILLMODE
,
6857 WINED3DRS_FOGDENSITY
,
6859 WINED3DRS_FOGSTART
,
6860 WINED3DRS_LASTPIXEL
,
6861 WINED3DRS_SHADEMODE
,
6862 WINED3DRS_SRCBLEND
,
6863 WINED3DRS_STENCILENABLE
,
6864 WINED3DRS_STENCILFAIL
,
6865 WINED3DRS_STENCILFUNC
,
6866 WINED3DRS_STENCILMASK
,
6867 WINED3DRS_STENCILPASS
,
6868 WINED3DRS_STENCILREF
,
6869 WINED3DRS_STENCILWRITEMASK
,
6870 WINED3DRS_STENCILZFAIL
,
6871 WINED3DRS_TEXTUREFACTOR
,
6882 WINED3DRS_ZWRITEENABLE
6885 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
6886 WINED3DTSS_ADDRESSW
,
6887 WINED3DTSS_ALPHAARG0
,
6888 WINED3DTSS_ALPHAARG1
,
6889 WINED3DTSS_ALPHAARG2
,
6890 WINED3DTSS_ALPHAOP
,
6891 WINED3DTSS_BUMPENVLOFFSET
,
6892 WINED3DTSS_BUMPENVLSCALE
,
6893 WINED3DTSS_BUMPENVMAT00
,
6894 WINED3DTSS_BUMPENVMAT01
,
6895 WINED3DTSS_BUMPENVMAT10
,
6896 WINED3DTSS_BUMPENVMAT11
,
6897 WINED3DTSS_COLORARG0
,
6898 WINED3DTSS_COLORARG1
,
6899 WINED3DTSS_COLORARG2
,
6900 WINED3DTSS_COLOROP
,
6901 WINED3DTSS_RESULTARG
,
6902 WINED3DTSS_TEXCOORDINDEX
,
6903 WINED3DTSS_TEXTURETRANSFORMFLAGS
6906 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
6907 WINED3DSAMP_ADDRESSU
,
6908 WINED3DSAMP_ADDRESSV
,
6909 WINED3DSAMP_ADDRESSW
,
6910 WINED3DSAMP_BORDERCOLOR
,
6911 WINED3DSAMP_MAGFILTER
,
6912 WINED3DSAMP_MINFILTER
,
6913 WINED3DSAMP_MIPFILTER
,
6914 WINED3DSAMP_MIPMAPLODBIAS
,
6915 WINED3DSAMP_MAXMIPLEVEL
,
6916 WINED3DSAMP_MAXANISOTROPY
,
6917 WINED3DSAMP_SRGBTEXTURE
,
6918 WINED3DSAMP_ELEMENTINDEX
6921 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
6923 WINED3DRS_AMBIENTMATERIALSOURCE
,
6924 WINED3DRS_CLIPPING
,
6925 WINED3DRS_CLIPPLANEENABLE
,
6926 WINED3DRS_COLORVERTEX
,
6927 WINED3DRS_DIFFUSEMATERIALSOURCE
,
6928 WINED3DRS_EMISSIVEMATERIALSOURCE
,
6929 WINED3DRS_FOGDENSITY
,
6931 WINED3DRS_FOGSTART
,
6932 WINED3DRS_FOGTABLEMODE
,
6933 WINED3DRS_FOGVERTEXMODE
,
6934 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
6935 WINED3DRS_LIGHTING
,
6936 WINED3DRS_LOCALVIEWER
,
6937 WINED3DRS_MULTISAMPLEANTIALIAS
,
6938 WINED3DRS_MULTISAMPLEMASK
,
6939 WINED3DRS_NORMALIZENORMALS
,
6940 WINED3DRS_PATCHEDGESTYLE
,
6941 WINED3DRS_POINTSCALE_A
,
6942 WINED3DRS_POINTSCALE_B
,
6943 WINED3DRS_POINTSCALE_C
,
6944 WINED3DRS_POINTSCALEENABLE
,
6945 WINED3DRS_POINTSIZE
,
6946 WINED3DRS_POINTSIZE_MAX
,
6947 WINED3DRS_POINTSIZE_MIN
,
6948 WINED3DRS_POINTSPRITEENABLE
,
6949 WINED3DRS_RANGEFOGENABLE
,
6950 WINED3DRS_SPECULARMATERIALSOURCE
,
6951 WINED3DRS_TWEENFACTOR
,
6952 WINED3DRS_VERTEXBLEND
6955 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
6956 WINED3DTSS_TEXCOORDINDEX
,
6957 WINED3DTSS_TEXTURETRANSFORMFLAGS
6960 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
6961 WINED3DSAMP_DMAPOFFSET
6964 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
6965 DWORD rep
= StateTable
[state
].representative
;
6969 if(!rep
|| isStateDirty(This
, rep
)) return;
6971 This
->dirtyArray
[This
->numDirtyEntries
++] = rep
;
6974 This
->isStateDirty
[idx
] |= (1 << shift
);