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 /* Transformed vertices are horribly inflexible. If the app specifies an
454 * vertex buffer with transformed vertices in default pool without DYNAMIC
455 * usage assume DYNAMIC usage and print a warning. The app will have to update
456 * the vertices regularily for them to be useful
458 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
459 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
460 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
461 vboUsage |= WINED3DUSAGE_DYNAMIC;
464 /* Don't use static, because dx apps tend to update the buffer
465 * quite often even if they specify 0 usage
467 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
468 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
469 TRACE("Gl usage = GL_STREAM_DRAW\n");
470 glUsage = GL_STREAM_DRAW_ARB;
472 case D3DUSAGE_WRITEONLY:
473 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
474 glUsage = GL_DYNAMIC_DRAW_ARB;
476 case D3DUSAGE_DYNAMIC:
477 TRACE("Gl usage = GL_STREAM_COPY\n");
478 glUsage = GL_STREAM_COPY_ARB;
481 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
482 glUsage = GL_DYNAMIC_COPY_ARB;
486 /* Reserve memory for the buffer. The amount of data won't change
487 * so we are safe with calling glBufferData once with a NULL ptr and
488 * calling glBufferSubData on updates
490 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
491 error = glGetError();
492 if(error != GL_NO_ERROR) {
493 WARN("glBufferDataARB failed with error %d\n", error);
501 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
502 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
503 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
505 object->Flags |= VBFLAG_VBOCREATEFAIL;
510 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
511 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
514 IWineD3DVertexBufferImpl *object;
515 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
516 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
518 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
520 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
521 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
523 if(Size == 0) return WINED3DERR_INVALIDCALL;
525 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
526 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
530 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
531 * drawStridedFast (half-life 2).
533 * Basically converting the vertices in the buffer is quite expensive, and observations
534 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
535 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
537 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
538 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
539 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
540 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
542 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
543 * more. In this call we can convert dx7 buffers too.
545 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
546 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
547 (dxVersion > 7 || !conv) ) {
550 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
551 if(dxVersion == 7 && object->vbo) {
552 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
553 object->resource.allocatedMemory = NULL;
560 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
561 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
562 HANDLE *sharedHandle, IUnknown *parent) {
563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
564 IWineD3DIndexBufferImpl *object;
565 TRACE("(%p) Creating index buffer\n", This);
567 /* Allocate the storage for the device */
568 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
571 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
572 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
575 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
576 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
577 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
582 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
585 IWineD3DStateBlockImpl *object;
589 D3DCREATEOBJECTINSTANCE(object, StateBlock)
590 object->blockType = Type;
592 /* Special case - Used during initialization to produce a placeholder stateblock
593 so other functions called can update a state block */
594 if (Type == WINED3DSBT_INIT) {
595 /* Don't bother increasing the reference count otherwise a device will never
596 be freed due to circular dependencies */
600 temp_result = allocate_shader_constants(object);
601 if (WINED3D_OK != temp_result)
604 /* Otherwise, might as well set the whole state block to the appropriate values */
605 if (This->stateBlock != NULL)
606 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
608 memset(object->streamFreq, 1, sizeof(object->streamFreq));
610 /* Reset the ref and type after kludging it */
611 object->wineD3DDevice = This;
613 object->blockType = Type;
615 TRACE("Updating changed flags appropriate for type %d\n", Type);
617 if (Type == WINED3DSBT_ALL) {
619 TRACE("ALL => Pretend everything has changed\n");
620 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
622 } else if (Type == WINED3DSBT_PIXELSTATE) {
624 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
625 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
627 object->changed.pixelShader = TRUE;
629 /* Pixel Shader Constants */
630 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
631 object->changed.pixelShaderConstantsF[i] = TRUE;
632 for (i = 0; i < MAX_CONST_B; ++i)
633 object->changed.pixelShaderConstantsB[i] = TRUE;
634 for (i = 0; i < MAX_CONST_I; ++i)
635 object->changed.pixelShaderConstantsI[i] = TRUE;
637 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
638 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
640 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
641 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
642 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
645 for (j = 0 ; j < 16; j++) {
646 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
648 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
652 } else if (Type == WINED3DSBT_VERTEXSTATE) {
654 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
655 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
657 object->changed.vertexShader = TRUE;
659 /* Vertex Shader Constants */
660 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
661 object->changed.vertexShaderConstantsF[i] = TRUE;
662 for (i = 0; i < MAX_CONST_B; ++i)
663 object->changed.vertexShaderConstantsB[i] = TRUE;
664 for (i = 0; i < MAX_CONST_I; ++i)
665 object->changed.vertexShaderConstantsI[i] = TRUE;
667 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
668 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
670 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
671 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
672 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
675 for (j = 0 ; j < 16; j++){
676 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
677 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
681 /* Duplicate light chain */
683 PLIGHTINFOEL *src = NULL;
684 PLIGHTINFOEL *dst = NULL;
685 PLIGHTINFOEL *newEl = NULL;
686 src = This->stateBlock->lights;
687 object->lights = NULL;
691 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
692 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
693 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
695 newEl->changed = TRUE;
696 newEl->enabledChanged = TRUE;
698 object->lights = newEl;
709 FIXME("Unrecognized state block type %d\n", Type);
712 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
717 /* ************************************
719 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
722 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
724 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.
726 ******************************** */
728 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) {
729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
730 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
731 unsigned int pow2Width, pow2Height;
732 unsigned int Size = 1;
733 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
734 TRACE("(%p) Create surface\n",This);
736 /** FIXME: Check ranges on the inputs are valid
739 * [in] Quality level. The valid range is between zero and one less than the level
740 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
741 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
742 * values of paired render targets, depth stencil surfaces, and the MultiSample type
744 *******************************/
749 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
751 * If this flag is set, the contents of the depth stencil buffer will be
752 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
753 * with a different depth surface.
755 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
756 ***************************/
758 if(MultisampleQuality < 0) {
759 FIXME("Invalid multisample level %d\n", MultisampleQuality);
760 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
763 if(MultisampleQuality > 0) {
764 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
765 MultisampleQuality=0;
768 /** FIXME: Check that the format is supported
770 *******************************/
772 /* Non-power2 support */
773 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
777 /* Find the nearest pow2 match */
778 pow2Width = pow2Height = 1;
779 while (pow2Width < Width) pow2Width <<= 1;
780 while (pow2Height < Height) pow2Height <<= 1;
783 if (pow2Width > Width || pow2Height > Height) {
784 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
785 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
786 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
787 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
788 This, Width, Height);
789 return WINED3DERR_NOTAVAILABLE;
793 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
794 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
796 *********************************/
797 if (WINED3DFMT_UNKNOWN == Format) {
799 } else if (Format == WINED3DFMT_DXT1) {
800 /* DXT1 is half byte per pixel */
801 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
803 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
804 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
805 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
807 /* The pitch is a multiple of 4 bytes */
808 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
812 /** Create and initialise the surface resource **/
813 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
814 /* "Standalone" surface */
815 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
817 object->currentDesc.Width = Width;
818 object->currentDesc.Height = Height;
819 object->currentDesc.MultiSampleType = MultiSample;
820 object->currentDesc.MultiSampleQuality = MultisampleQuality;
822 /* Setup some glformat defaults */
823 object->glDescription.glFormat = tableEntry->glFormat;
824 object->glDescription.glFormatInternal = tableEntry->glInternal;
825 object->glDescription.glType = tableEntry->glType;
827 object->glDescription.textureName = 0;
828 object->glDescription.level = Level;
829 object->glDescription.target = GL_TEXTURE_2D;
832 object->pow2Width = pow2Width;
833 object->pow2Height = pow2Height;
836 object->Flags = 0; /* We start without flags set */
837 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
838 object->Flags |= Discard ? SFLAG_DISCARD : 0;
839 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
840 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
843 if (WINED3DFMT_UNKNOWN != Format) {
844 object->bytesPerPixel = tableEntry->bpp;
845 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
846 object->pow2Size *= pow2Height;
848 object->bytesPerPixel = 0;
849 object->pow2Size = 0;
852 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
854 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
856 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
857 * this function is too deep to need to care about things like this.
858 * Levels need to be checked too, and possibly Type since they all affect what can be done.
859 * ****************************************/
861 case WINED3DPOOL_SCRATCH:
863 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
864 which are mutually exclusive, setting lockable to true\n");
867 case WINED3DPOOL_SYSTEMMEM:
868 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
869 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
870 case WINED3DPOOL_MANAGED:
871 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
872 Usage of DYNAMIC which are mutually exclusive, not doing \
873 anything just telling you.\n");
875 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
876 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
877 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
878 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
881 FIXME("(%p) Unknown pool %d\n", This, Pool);
885 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
886 FIXME("Trying to create a render target that isn't in the default pool\n");
889 /* mark the texture as dirty so that it gets loaded first time around*/
890 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
891 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
892 This, Width, Height, Format, debug_d3dformat(Format),
893 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
895 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
896 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
897 This->ddraw_primary = (IWineD3DSurface *) object;
899 /* Look at the implementation and set the correct Vtable */
902 /* Nothing to do, it's set already */
906 object->lpVtbl = &IWineGDISurface_Vtbl;
910 /* To be sure to catch this */
911 ERR("Unknown requested surface implementation %d!\n", Impl);
912 IWineD3DSurface_Release((IWineD3DSurface *) object);
913 return WINED3DERR_INVALIDCALL;
916 /* Call the private setup routine */
917 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
921 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
922 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
923 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
924 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DTextureImpl *object;
932 unsigned int pow2Width;
933 unsigned int pow2Height;
936 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
937 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
938 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
940 /* TODO: It should only be possible to create textures for formats
941 that are reported as supported */
942 if (WINED3DFMT_UNKNOWN >= Format) {
943 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
944 return WINED3DERR_INVALIDCALL;
947 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
948 D3DINITIALIZEBASETEXTURE(object->baseTexture);
949 object->width = Width;
950 object->height = Height;
952 /** Non-power2 support **/
953 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
957 /* Find the nearest pow2 match */
958 pow2Width = pow2Height = 1;
959 while (pow2Width < Width) pow2Width <<= 1;
960 while (pow2Height < Height) pow2Height <<= 1;
963 /** FIXME: add support for real non-power-two if it's provided by the video card **/
964 /* Precalculated scaling for 'faked' non power of two texture coords */
965 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
966 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
967 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
969 /* Calculate levels for mip mapping */
971 TRACE("calculating levels %d\n", object->baseTexture.levels);
972 object->baseTexture.levels++;
975 while (tmpW > 1 || tmpH > 1) {
976 tmpW = max(1, tmpW >> 1);
977 tmpH = max(1, tmpH >> 1);
978 object->baseTexture.levels++;
980 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
983 /* Generate all the surfaces */
986 for (i = 0; i < object->baseTexture.levels; i++)
988 /* use the callback to create the texture surface */
989 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
990 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
991 FIXME("Failed to create surface %p\n", object);
993 object->surfaces[i] = NULL;
994 IWineD3DTexture_Release((IWineD3DTexture *)object);
1000 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1001 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1002 /* calculate the next mipmap level */
1003 tmpW = max(1, tmpW >> 1);
1004 tmpH = max(1, tmpH >> 1);
1007 TRACE("(%p) : Created texture %p\n", This, object);
1011 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1012 UINT Width, UINT Height, UINT Depth,
1013 UINT Levels, DWORD Usage,
1014 WINED3DFORMAT Format, WINED3DPOOL Pool,
1015 IWineD3DVolumeTexture **ppVolumeTexture,
1016 HANDLE *pSharedHandle, IUnknown *parent,
1017 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1020 IWineD3DVolumeTextureImpl *object;
1026 /* TODO: It should only be possible to create textures for formats
1027 that are reported as supported */
1028 if (WINED3DFMT_UNKNOWN >= Format) {
1029 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1030 return WINED3DERR_INVALIDCALL;
1033 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1034 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1036 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1037 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1039 object->width = Width;
1040 object->height = Height;
1041 object->depth = Depth;
1043 /* Calculate levels for mip mapping */
1045 object->baseTexture.levels++;
1049 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1050 tmpW = max(1, tmpW >> 1);
1051 tmpH = max(1, tmpH >> 1);
1052 tmpD = max(1, tmpD >> 1);
1053 object->baseTexture.levels++;
1055 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1058 /* Generate all the surfaces */
1063 for (i = 0; i < object->baseTexture.levels; i++)
1065 /* Create the volume */
1066 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1067 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1069 /* Set its container to this object */
1070 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1072 /* calcualte the next mipmap level */
1073 tmpW = max(1, tmpW >> 1);
1074 tmpH = max(1, tmpH >> 1);
1075 tmpD = max(1, tmpD >> 1);
1078 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1079 TRACE("(%p) : Created volume texture %p\n", This, object);
1083 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1084 UINT Width, UINT Height, UINT Depth,
1086 WINED3DFORMAT Format, WINED3DPOOL Pool,
1087 IWineD3DVolume** ppVolume,
1088 HANDLE* pSharedHandle, IUnknown *parent) {
1090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1091 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1092 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1094 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1096 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1097 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1099 object->currentDesc.Width = Width;
1100 object->currentDesc.Height = Height;
1101 object->currentDesc.Depth = Depth;
1102 object->bytesPerPixel = formatDesc->bpp;
1104 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1105 object->lockable = TRUE;
1106 object->locked = FALSE;
1107 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1108 object->dirty = TRUE;
1110 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1113 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1114 UINT Levels, DWORD Usage,
1115 WINED3DFORMAT Format, WINED3DPOOL Pool,
1116 IWineD3DCubeTexture **ppCubeTexture,
1117 HANDLE *pSharedHandle, IUnknown *parent,
1118 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1121 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1125 unsigned int pow2EdgeLength = EdgeLength;
1127 /* TODO: It should only be possible to create textures for formats
1128 that are reported as supported */
1129 if (WINED3DFMT_UNKNOWN >= Format) {
1130 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1131 return WINED3DERR_INVALIDCALL;
1134 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1135 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 TRACE("(%p) Create Cube Texture\n", This);
1139 /** Non-power2 support **/
1141 /* Find the nearest pow2 match */
1143 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1145 object->edgeLength = EdgeLength;
1146 /* TODO: support for native non-power 2 */
1147 /* Precalculated scaling for 'faked' non power of two texture coords */
1148 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1150 /* Calculate levels for mip mapping */
1152 object->baseTexture.levels++;
1155 tmpW = max(1, tmpW >> 1);
1156 object->baseTexture.levels++;
1158 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1161 /* Generate all the surfaces */
1163 for (i = 0; i < object->baseTexture.levels; i++) {
1165 /* Create the 6 faces */
1166 for (j = 0; j < 6; j++) {
1168 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1169 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1171 if(hr!= WINED3D_OK) {
1175 for (l = 0; l < j; l++) {
1176 IWineD3DSurface_Release(object->surfaces[j][i]);
1178 for (k = 0; k < i; k++) {
1179 for (l = 0; l < 6; l++) {
1180 IWineD3DSurface_Release(object->surfaces[l][j]);
1184 FIXME("(%p) Failed to create surface\n",object);
1185 HeapFree(GetProcessHeap(),0,object);
1186 *ppCubeTexture = NULL;
1189 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1190 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1192 tmpW = max(1, tmpW >> 1);
1195 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1196 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1200 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1202 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1204 if (NULL == ppQuery) {
1205 /* Just a check to see if we support this type of query */
1206 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1208 case WINED3DQUERYTYPE_OCCLUSION:
1209 TRACE("(%p) occlusion query\n", This);
1210 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1213 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1215 case WINED3DQUERYTYPE_VCACHE:
1216 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1217 case WINED3DQUERYTYPE_VERTEXSTATS:
1218 case WINED3DQUERYTYPE_EVENT:
1219 case WINED3DQUERYTYPE_TIMESTAMP:
1220 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1221 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1222 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1223 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1224 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1225 case WINED3DQUERYTYPE_PIXELTIMINGS:
1226 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1227 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1229 FIXME("(%p) Unhandled query type %d\n", This, Type);
1234 D3DCREATEOBJECTINSTANCE(object, Query)
1235 object->type = Type;
1236 /* allocated the 'extended' data based on the type of query requested */
1238 case WINED3DQUERYTYPE_OCCLUSION:
1239 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1240 TRACE("(%p) Allocating data for an occlusion query\n", This);
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1242 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1245 case WINED3DQUERYTYPE_VCACHE:
1246 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1247 case WINED3DQUERYTYPE_VERTEXSTATS:
1248 case WINED3DQUERYTYPE_EVENT:
1249 case WINED3DQUERYTYPE_TIMESTAMP:
1250 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1251 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1252 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1253 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1254 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1255 case WINED3DQUERYTYPE_PIXELTIMINGS:
1256 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1257 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1259 object->extendedData = 0;
1260 FIXME("(%p) Unhandled query type %d\n",This , Type);
1262 TRACE("(%p) : Created Query %p\n", This, object);
1266 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1269 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1270 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1276 XVisualInfo template;
1277 GLXContext oldContext;
1278 Drawable oldDrawable;
1279 HRESULT hr = WINED3D_OK;
1281 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1283 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1284 * does a device hold a reference to a swap chain giving them a lifetime of the device
1285 * or does the swap chain notify the device of its destruction.
1286 *******************************/
1288 /* Check the params */
1289 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1290 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1291 return WINED3DERR_INVALIDCALL;
1292 } else if (*pPresentationParameters->BackBufferCount > 1) {
1293 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");
1296 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1298 /*********************
1299 * Lookup the window Handle and the relating X window handle
1300 ********************/
1302 /* Setup hwnd we are using, plus which display this equates to */
1303 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1304 if (!object->win_handle) {
1305 object->win_handle = This->createParms.hFocusWindow;
1308 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1309 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1310 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1311 return WINED3DERR_NOTAVAILABLE;
1313 hDc = GetDC(object->win_handle);
1314 object->display = get_display(hDc);
1315 ReleaseDC(object->win_handle, hDc);
1316 TRACE("Using a display of %p %p\n", object->display, hDc);
1318 if (NULL == object->display || NULL == hDc) {
1319 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1320 return WINED3DERR_NOTAVAILABLE;
1323 if (object->win == 0) {
1324 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1325 return WINED3DERR_NOTAVAILABLE;
1328 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1329 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1332 * Create an opengl context for the display visual
1333 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1334 * use different properties after that point in time. FIXME: How to handle when requested format
1335 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1336 * it chooses is identical to the one already being used!
1337 **********************************/
1339 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1342 /* Create a new context for this swapchain */
1343 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1344 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1345 (or the best possible if none is requested) */
1346 TRACE("Found x visual ID : %ld\n", template.visualid);
1348 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1349 if (NULL == object->visInfo) {
1350 ERR("cannot really get XVisual\n");
1352 return WINED3DERR_NOTAVAILABLE;
1355 /* Write out some debug info about the visual/s */
1356 TRACE("Using x visual ID : %ld\n", template.visualid);
1357 TRACE(" visual info: %p\n", object->visInfo);
1358 TRACE(" num items : %d\n", num);
1359 for (n = 0;n < num; n++) {
1360 TRACE("=====item=====: %d\n", n + 1);
1361 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1362 TRACE(" screen : %d\n", object->visInfo[n].screen);
1363 TRACE(" depth : %u\n", object->visInfo[n].depth);
1364 TRACE(" class : %d\n", object->visInfo[n].class);
1365 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1366 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1367 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1368 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1369 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1370 /* log some extra glx info */
1371 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1372 TRACE(" gl_aux_buffers : %d\n", value);
1373 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1374 TRACE(" gl_buffer_size : %d\n", value);
1375 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1376 TRACE(" gl_red_size : %d\n", value);
1377 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1378 TRACE(" gl_green_size : %d\n", value);
1379 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1380 TRACE(" gl_blue_size : %d\n", value);
1381 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1382 TRACE(" gl_alpha_size : %d\n", value);
1383 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1384 TRACE(" gl_depth_size : %d\n", value);
1385 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1386 TRACE(" gl_stencil_size : %d\n", value);
1388 /* Now choose a similar visual ID*/
1390 #ifdef USE_CONTEXT_MANAGER
1392 /** TODO: use a context mamager **/
1396 IWineD3DSwapChain *implSwapChain;
1397 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1398 /* The first time around we create the context that is shared with all other swapchains and render targets */
1399 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1400 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1403 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1404 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1405 /* and create a new context with the implicit swapchains context as the shared context */
1406 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1407 IWineD3DSwapChain_Release(implSwapChain);
1412 XFree(object->visInfo);
1413 object->visInfo = NULL;
1417 if (!object->glCtx) {
1418 ERR("Failed to create GLX context\n");
1419 return WINED3DERR_NOTAVAILABLE;
1421 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1422 object->win_handle, object->glCtx, object->win, object->visInfo);
1425 /*********************
1426 * Windowed / Fullscreen
1427 *******************/
1430 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1431 * so we should really check to see if there is a fullscreen swapchain already
1432 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1433 **************************************/
1435 if (!*(pPresentationParameters->Windowed)) {
1442 /* Get info on the current display setup */
1444 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1447 /* Change the display settings */
1448 memset(&devmode, 0, sizeof(DEVMODEW));
1449 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1450 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1451 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1452 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1453 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1454 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1456 /* Make popup window */
1457 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1458 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1459 *(pPresentationParameters->BackBufferWidth),
1460 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1462 /* For GetDisplayMode */
1463 This->ddraw_width = devmode.dmPelsWidth;
1464 This->ddraw_height = devmode.dmPelsHeight;
1465 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1467 /* And finally clip mouse to our screen */
1468 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1469 ClipCursor(&clip_rc);
1473 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1474 * then the corresponding dimension of the client area of the hDeviceWindow
1475 * (or the focus window, if hDeviceWindow is NULL) is taken.
1476 **********************/
1478 if (*(pPresentationParameters->Windowed) &&
1479 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1480 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1483 GetClientRect(object->win_handle, &Rect);
1485 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1486 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1487 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1489 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1490 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1491 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1495 /*********************
1496 * finish off parameter initialization
1497 *******************/
1499 /* Put the correct figures in the presentation parameters */
1500 TRACE("Copying across presentation parameters\n");
1501 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1502 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1503 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1504 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1505 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1506 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1507 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1508 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1509 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1510 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1511 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1512 object->presentParms.Flags = *(pPresentationParameters->Flags);
1513 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1514 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1517 /*********************
1518 * Create the back, front and stencil buffers
1519 *******************/
1521 TRACE("calling rendertarget CB\n");
1522 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1524 object->presentParms.BackBufferWidth,
1525 object->presentParms.BackBufferHeight,
1526 object->presentParms.BackBufferFormat,
1527 object->presentParms.MultiSampleType,
1528 object->presentParms.MultiSampleQuality,
1529 TRUE /* Lockable */,
1530 &object->frontBuffer,
1531 NULL /* pShared (always null)*/);
1532 if (object->frontBuffer != NULL)
1533 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1535 if(object->presentParms.BackBufferCount > 0) {
1538 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1539 if(!object->backBuffer) {
1540 ERR("Out of memory\n");
1542 if (object->frontBuffer) {
1543 IUnknown *bufferParent;
1544 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1545 IUnknown_Release(bufferParent); /* once for the get parent */
1546 if (IUnknown_Release(bufferParent) > 0) {
1547 FIXME("(%p) Something's still holding the front buffer\n",This);
1550 HeapFree(GetProcessHeap(), 0, object);
1551 return E_OUTOFMEMORY;
1554 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1555 TRACE("calling rendertarget CB\n");
1556 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1558 object->presentParms.BackBufferWidth,
1559 object->presentParms.BackBufferHeight,
1560 object->presentParms.BackBufferFormat,
1561 object->presentParms.MultiSampleType,
1562 object->presentParms.MultiSampleQuality,
1563 TRUE /* Lockable */,
1564 &object->backBuffer[i],
1565 NULL /* pShared (always null)*/);
1566 if(hr == WINED3D_OK && object->backBuffer[i]) {
1567 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1573 object->backBuffer = NULL;
1576 if (object->backBuffer != NULL) {
1578 glDrawBuffer(GL_BACK);
1579 checkGLcall("glDrawBuffer(GL_BACK)");
1582 /* Single buffering - draw to front buffer */
1584 glDrawBuffer(GL_FRONT);
1585 checkGLcall("glDrawBuffer(GL_FRONT)");
1589 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1590 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1591 TRACE("Creating depth stencil buffer\n");
1592 if (This->depthStencilBuffer == NULL ) {
1593 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1595 object->presentParms.BackBufferWidth,
1596 object->presentParms.BackBufferHeight,
1597 object->presentParms.AutoDepthStencilFormat,
1598 object->presentParms.MultiSampleType,
1599 object->presentParms.MultiSampleQuality,
1600 FALSE /* FIXME: Discard */,
1601 &This->depthStencilBuffer,
1602 NULL /* pShared (always null)*/ );
1603 if (This->depthStencilBuffer != NULL)
1604 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1607 /** TODO: A check on width, height and multisample types
1608 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1609 ****************************/
1610 object->wantsDepthStencilBuffer = TRUE;
1612 object->wantsDepthStencilBuffer = FALSE;
1615 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1618 /*********************
1619 * init the default renderTarget management
1620 *******************/
1621 object->drawable = object->win;
1622 object->render_ctx = object->glCtx;
1624 if (hr == WINED3D_OK) {
1625 /*********************
1626 * Setup some defaults and clear down the buffers
1627 *******************/
1629 /** save current context and drawable **/
1630 oldContext = glXGetCurrentContext();
1631 oldDrawable = glXGetCurrentDrawable();
1633 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1634 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1635 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1637 checkGLcall("glXMakeCurrent");
1639 TRACE("Setting up the screen\n");
1640 /* Clear the screen */
1641 glClearColor(1.0, 0.0, 0.0, 0.0);
1642 checkGLcall("glClearColor");
1645 glClearStencil(0xffff);
1647 checkGLcall("glClear");
1649 glColor3f(1.0, 1.0, 1.0);
1650 checkGLcall("glColor3f");
1652 glEnable(GL_LIGHTING);
1653 checkGLcall("glEnable");
1655 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1656 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1658 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1659 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1661 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1662 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1664 /* switch back to the original context (if there was one)*/
1665 if (This->swapchains) {
1666 /** TODO: restore the context and drawable **/
1667 glXMakeCurrent(object->display, oldDrawable, oldContext);
1670 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1671 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1672 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1673 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1674 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1678 TRACE("Set swapchain to %p\n", object);
1679 } else { /* something went wrong so clean up */
1680 IUnknown* bufferParent;
1681 if (object->frontBuffer) {
1683 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1684 IUnknown_Release(bufferParent); /* once for the get parent */
1685 if (IUnknown_Release(bufferParent) > 0) {
1686 FIXME("(%p) Something's still holding the front buffer\n",This);
1689 if (object->backBuffer) {
1691 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1692 if(object->backBuffer[i]) {
1693 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1694 IUnknown_Release(bufferParent); /* once for the get parent */
1695 if (IUnknown_Release(bufferParent) > 0) {
1696 FIXME("(%p) Something's still holding the back buffer\n",This);
1700 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1701 object->backBuffer = NULL;
1703 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1704 /* Clean up the context */
1705 /* check that we are the current context first (we shouldn't be though!) */
1706 if (object->glCtx != 0) {
1707 if(glXGetCurrentContext() == object->glCtx) {
1708 glXMakeCurrent(object->display, None, NULL);
1710 glXDestroyContext(object->display, object->glCtx);
1712 HeapFree(GetProcessHeap(), 0, object);
1719 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1720 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 TRACE("(%p)\n", This);
1724 return This->NumberOfSwapChains;
1727 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1729 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1731 if(iSwapChain < This->NumberOfSwapChains) {
1732 *pSwapChain = This->swapchains[iSwapChain];
1733 IWineD3DSwapChain_AddRef(*pSwapChain);
1734 TRACE("(%p) returning %p\n", This, *pSwapChain);
1737 TRACE("Swapchain out of range\n");
1739 return WINED3DERR_INVALIDCALL;
1744 * Vertex Declaration
1746 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1748 IWineD3DVertexDeclarationImpl *object = NULL;
1749 HRESULT hr = WINED3D_OK;
1750 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1751 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1754 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1759 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1760 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1762 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1763 HRESULT hr = WINED3D_OK;
1764 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1765 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1767 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1769 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1770 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1771 if (pDeclaration != NULL) {
1772 IWineD3DVertexDeclaration *vertexDeclaration;
1773 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1774 if (WINED3D_OK == hr) {
1775 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1776 object->vertexDeclaration = vertexDeclaration;
1778 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1779 IWineD3DVertexShader_Release(*ppVertexShader);
1780 return WINED3DERR_INVALIDCALL;
1784 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1786 if (WINED3D_OK != hr) {
1787 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1788 IWineD3DVertexShader_Release(*ppVertexShader);
1789 return WINED3DERR_INVALIDCALL;
1792 #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. */
1793 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1804 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1806 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1807 HRESULT hr = WINED3D_OK;
1809 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1810 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1811 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1812 if (WINED3D_OK == hr) {
1813 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1815 WARN("(%p) : Failed to create pixel shader\n", This);
1821 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1823 IWineD3DPaletteImpl *object;
1825 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1827 /* Create the new object */
1828 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1830 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1831 return E_OUTOFMEMORY;
1834 object->lpVtbl = &IWineD3DPalette_Vtbl;
1836 object->Flags = Flags;
1837 object->parent = Parent;
1838 object->wineD3DDevice = This;
1839 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1841 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1844 HeapFree( GetProcessHeap(), 0, object);
1845 return E_OUTOFMEMORY;
1848 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1850 IWineD3DPalette_Release((IWineD3DPalette *) object);
1854 *Palette = (IWineD3DPalette *) object;
1859 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1861 IWineD3DSwapChainImpl *swapchain;
1864 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1865 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1867 /* TODO: Test if OpenGL is compiled in and loaded */
1869 /* Initialize the texture unit mapping to a 1:1 mapping */
1870 for(state = 0; state < MAX_SAMPLERS; state++) {
1871 This->texUnitMap[state] = state;
1873 This->oneToOneTexUnitMap = TRUE;
1875 /* Setup the implicit swapchain */
1876 TRACE("Creating implicit swapchain\n");
1877 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
1878 WARN("Failed to create implicit swapchain\n");
1879 return WINED3DERR_INVALIDCALL;
1882 This->NumberOfSwapChains = 1;
1883 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1884 if(!This->swapchains) {
1885 ERR("Out of memory!\n");
1886 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1887 return E_OUTOFMEMORY;
1889 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1891 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1892 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1893 This->render_targets[0] = swapchain->backBuffer[0];
1896 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1897 This->render_targets[0] = swapchain->frontBuffer;
1899 IWineD3DSurface_AddRef(This->render_targets[0]);
1900 /* Depth Stencil support */
1901 This->stencilBufferTarget = This->depthStencilBuffer;
1902 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1903 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1905 if (NULL != This->stencilBufferTarget) {
1906 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1909 /* Set up some starting GL setup */
1912 * Initialize openGL extension related variables
1913 * with Default values
1916 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
1917 /* Setup all the devices defaults */
1918 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1920 IWineD3DImpl_CheckGraphicsMemory();
1924 /* Initialize our list of GLSL programs */
1925 list_init(&This->glsl_shader_progs);
1927 { /* Set a default viewport */
1931 vp.Width = *(pPresentationParameters->BackBufferWidth);
1932 vp.Height = *(pPresentationParameters->BackBufferHeight);
1935 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1938 /* Initialize the current view state */
1939 This->modelview_valid = 1;
1940 This->proj_valid = 0;
1941 This->view_ident = 1;
1942 This->last_was_rhw = 0;
1943 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1944 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1946 /* Clear the screen */
1947 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1949 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
1950 * This might create a problem in 2 situations:
1951 * ->The D3D default value is 0, but the opengl default value is something else
1952 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
1954 for(state = 0; state <= STATE_HIGHEST; state++) {
1955 IWineD3DDeviceImpl_MarkStateDirty(This, state);
1958 This->d3d_initialized = TRUE;
1962 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1966 TRACE("(%p)\n", This);
1968 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1970 /* Delete the mouse cursor texture */
1971 if(This->cursorTexture) {
1973 glDeleteTextures(1, &This->cursorTexture);
1975 This->cursorTexture = 0;
1978 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1979 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1982 /* Release the buffers (with sanity checks)*/
1983 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1984 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1985 if(This->depthStencilBuffer != This->stencilBufferTarget)
1986 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1988 This->stencilBufferTarget = NULL;
1990 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1991 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1992 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1994 TRACE("Setting rendertarget to NULL\n");
1995 This->render_targets[0] = NULL;
1997 if (This->depthStencilBuffer) {
1998 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1999 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2001 This->depthStencilBuffer = NULL;
2004 for(i=0; i < This->NumberOfSwapChains; i++) {
2005 TRACE("Releasing the implicit swapchain %d\n", i);
2006 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2007 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2011 HeapFree(GetProcessHeap(), 0, This->swapchains);
2012 This->swapchains = NULL;
2013 This->NumberOfSwapChains = 0;
2015 This->d3d_initialized = FALSE;
2019 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2021 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2023 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2024 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2025 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2028 This->ddraw_fullscreen = fullscreen;
2031 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2036 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2038 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2040 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2041 /* Ignore some modes if a description was passed */
2042 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2043 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2044 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2046 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2048 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2055 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2059 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2062 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2064 /* Resize the screen even without a window:
2065 * The app could have unset it with SetCooperativeLevel, but not called
2066 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2067 * but we don't have any hwnd
2070 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2071 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2072 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2073 devmode.dmPelsWidth = pMode->Width;
2074 devmode.dmPelsHeight = pMode->Height;
2076 devmode.dmDisplayFrequency = pMode->RefreshRate;
2077 if (pMode->RefreshRate != 0) {
2078 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2081 /* Only change the mode if necessary */
2082 if( (This->ddraw_width == pMode->Width) &&
2083 (This->ddraw_height == pMode->Height) &&
2084 (This->ddraw_format == pMode->Format) &&
2085 (pMode->RefreshRate == 0) ) {
2089 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2090 if (ret != DISP_CHANGE_SUCCESSFUL) {
2091 if(devmode.dmDisplayFrequency != 0) {
2092 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2093 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2094 devmode.dmDisplayFrequency = 0;
2095 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2097 if(ret != DISP_CHANGE_SUCCESSFUL) {
2098 return DDERR_INVALIDMODE;
2102 /* Store the new values */
2103 This->ddraw_width = pMode->Width;
2104 This->ddraw_height = pMode->Height;
2105 This->ddraw_format = pMode->Format;
2107 /* Only do this with a window of course */
2108 if(This->ddraw_window)
2109 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2111 /* And finally clip mouse to our screen */
2112 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2113 ClipCursor(&clip_rc);
2118 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2120 *ppD3D= This->wineD3D;
2121 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2122 IWineD3D_AddRef(*ppD3D);
2126 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2127 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2128 * into the video ram as possible and seeing how many fit
2129 * you can also get the correct initial value from nvidia and ATI's driver via X
2130 * texture memory is video memory + AGP memory
2131 *******************/
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 static BOOL showfixmes = TRUE;
2135 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2136 (wined3d_settings.emulated_textureram/(1024*1024)),
2137 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2140 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2141 (wined3d_settings.emulated_textureram/(1024*1024)),
2142 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2143 /* return simulated texture memory left */
2144 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2152 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2155 /* Update the current state block */
2156 This->updateStateBlock->fvf = fvf;
2157 This->updateStateBlock->changed.fvf = TRUE;
2158 This->updateStateBlock->set.fvf = TRUE;
2160 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2166 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2168 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2169 *pfvf = This->stateBlock->fvf;
2174 * Get / Set Stream Source
2176 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2178 IWineD3DVertexBuffer *oldSrc;
2180 /**TODO: instance and index data, see
2181 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2183 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2186 /* D3d9 only, but shouldn't hurt d3d8 */
2189 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2191 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2192 FIXME("stream index data not supported\n");
2194 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2195 FIXME("stream instance data not supported\n");
2199 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2201 if (StreamNumber >= MAX_STREAMS) {
2202 WARN("Stream out of range %d\n", StreamNumber);
2203 return WINED3DERR_INVALIDCALL;
2206 oldSrc = This->stateBlock->streamSource[StreamNumber];
2207 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2209 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2210 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2211 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2213 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2214 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2216 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2218 /* Handle recording of state blocks */
2219 if (This->isRecordingState) {
2220 TRACE("Recording... not performing anything\n");
2224 /* Same stream object: no action */
2225 if (oldSrc == pStreamData)
2228 /* Need to do a getParent and pass the reffs up */
2229 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2230 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2231 so for now, just count internally */
2232 if (pStreamData != NULL) {
2233 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2234 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2235 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2237 vbImpl->stream = StreamNumber;
2238 vbImpl->Flags |= VBFLAG_STREAM;
2239 IWineD3DVertexBuffer_AddRef(pStreamData);
2241 if (oldSrc != NULL) {
2242 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2243 IWineD3DVertexBuffer_Release(oldSrc);
2246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2251 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2256 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2259 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2261 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2262 FIXME("stream index data not supported\n");
2264 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2265 FIXME("stream instance data not supported\n");
2269 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2271 if (StreamNumber >= MAX_STREAMS) {
2272 WARN("Stream out of range %d\n", StreamNumber);
2273 return WINED3DERR_INVALIDCALL;
2275 *pStream = This->stateBlock->streamSource[StreamNumber];
2276 *pStride = This->stateBlock->streamStride[StreamNumber];
2278 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2281 if (*pStream != NULL) {
2282 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2287 /*Should be quite easy, just an extension of vertexdata
2289 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2291 The divider is a bit odd though
2293 VertexOffset = StartVertex / Divider * StreamStride +
2294 VertexIndex / Divider * StreamStride + StreamOffset
2297 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2300 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2301 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2303 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2304 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2305 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2307 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2308 FIXME("Stream indexing not fully supported\n");
2314 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2317 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2318 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2320 TRACE("(%p) : returning %d\n", This, *Divider);
2326 * Get / Set & Multiply Transform
2328 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2331 /* Most of this routine, comments included copied from ddraw tree initially: */
2332 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2334 /* Handle recording of state blocks */
2335 if (This->isRecordingState) {
2336 TRACE("Recording... not performing anything\n");
2337 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2338 This->updateStateBlock->set.transform[d3dts] = TRUE;
2339 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2344 * If the new matrix is the same as the current one,
2345 * we cut off any further processing. this seems to be a reasonable
2346 * optimization because as was noticed, some apps (warcraft3 for example)
2347 * tend towards setting the same matrix repeatedly for some reason.
2349 * From here on we assume that the new matrix is different, wherever it matters.
2351 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2352 TRACE("The app is setting the same matrix over again\n");
2355 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2359 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2360 where ViewMat = Camera space, WorldMat = world space.
2362 In OpenGL, camera and world space is combined into GL_MODELVIEW
2363 matrix. The Projection matrix stay projection matrix.
2366 /* Capture the times we can just ignore the change for now */
2367 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2368 This->modelview_valid = FALSE;
2371 } else if (d3dts == WINED3DTS_PROJECTION) {
2372 This->proj_valid = FALSE;
2375 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2376 /* Indexed Vertex Blending Matrices 256 -> 511 */
2377 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2378 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2382 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2383 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2384 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2385 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2386 /* Handled by the state manager */
2387 } else { /* What was requested!?? */
2388 WARN("invalid matrix specified: %i\n", d3dts);
2391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2395 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2397 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2398 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2402 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2403 WINED3DMATRIX *mat = NULL;
2406 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2407 * below means it will be recorded in a state block change, but it
2408 * works regardless where it is recorded.
2409 * If this is found to be wrong, change to StateBlock.
2411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2412 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2414 if (State < HIGHEST_TRANSFORMSTATE)
2416 mat = &This->updateStateBlock->transforms[State];
2418 FIXME("Unhandled transform state!!\n");
2421 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2423 /* Apply change via set transform - will reapply to eg. lights this way */
2424 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2430 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2431 you can reference any indexes you want as long as that number max are enabled at any
2432 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2433 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2434 but when recording, just build a chain pretty much of commands to be replayed. */
2436 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2438 PLIGHTINFOEL *object, *temp;
2440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2441 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2443 /* If recording state block, just add to end of lights chain */
2444 if (This->isRecordingState) {
2445 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2446 if (NULL == object) {
2447 return WINED3DERR_OUTOFVIDEOMEMORY;
2449 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2450 object->OriginalIndex = Index;
2451 object->glIndex = -1;
2452 object->changed = TRUE;
2454 /* Add to the END of the chain of lights changes to be replayed */
2455 if (This->updateStateBlock->lights == NULL) {
2456 This->updateStateBlock->lights = object;
2458 temp = This->updateStateBlock->lights;
2459 while (temp->next != NULL) temp=temp->next;
2460 temp->next = object;
2462 TRACE("Recording... not performing anything more\n");
2466 /* Ok, not recording any longer so do real work */
2467 object = This->stateBlock->lights;
2468 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2470 /* If we didn't find it in the list of lights, time to add it */
2471 if (object == NULL) {
2472 PLIGHTINFOEL *insertAt,*prevPos;
2474 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2475 if (NULL == object) {
2476 return WINED3DERR_OUTOFVIDEOMEMORY;
2478 object->OriginalIndex = Index;
2479 object->glIndex = -1;
2481 /* Add it to the front of list with the idea that lights will be changed as needed
2482 BUT after any lights currently assigned GL indexes */
2483 insertAt = This->stateBlock->lights;
2485 while (insertAt != NULL && insertAt->glIndex != -1) {
2487 insertAt = insertAt->next;
2490 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2491 This->stateBlock->lights = object;
2492 } else if (insertAt == NULL) { /* End of list */
2493 prevPos->next = object;
2494 object->prev = prevPos;
2495 } else { /* Middle of chain */
2496 if (prevPos == NULL) {
2497 This->stateBlock->lights = object;
2499 prevPos->next = object;
2501 object->prev = prevPos;
2502 object->next = insertAt;
2503 insertAt->prev = object;
2507 /* Initialize the object */
2508 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,
2509 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2510 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2511 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2512 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2513 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2514 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2516 /* Save away the information */
2517 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2519 switch (pLight->Type) {
2520 case WINED3DLIGHT_POINT:
2522 object->lightPosn[0] = pLight->Position.x;
2523 object->lightPosn[1] = pLight->Position.y;
2524 object->lightPosn[2] = pLight->Position.z;
2525 object->lightPosn[3] = 1.0f;
2526 object->cutoff = 180.0f;
2530 case WINED3DLIGHT_DIRECTIONAL:
2532 object->lightPosn[0] = -pLight->Direction.x;
2533 object->lightPosn[1] = -pLight->Direction.y;
2534 object->lightPosn[2] = -pLight->Direction.z;
2535 object->lightPosn[3] = 0.0;
2536 object->exponent = 0.0f;
2537 object->cutoff = 180.0f;
2540 case WINED3DLIGHT_SPOT:
2542 object->lightPosn[0] = pLight->Position.x;
2543 object->lightPosn[1] = pLight->Position.y;
2544 object->lightPosn[2] = pLight->Position.z;
2545 object->lightPosn[3] = 1.0;
2548 object->lightDirn[0] = pLight->Direction.x;
2549 object->lightDirn[1] = pLight->Direction.y;
2550 object->lightDirn[2] = pLight->Direction.z;
2551 object->lightDirn[3] = 1.0;
2554 * opengl-ish and d3d-ish spot lights use too different models for the
2555 * light "intensity" as a function of the angle towards the main light direction,
2556 * so we only can approximate very roughly.
2557 * however spot lights are rather rarely used in games (if ever used at all).
2558 * furthermore if still used, probably nobody pays attention to such details.
2560 if (pLight->Falloff == 0) {
2563 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2565 if (rho < 0.0001) rho = 0.0001f;
2566 object->exponent = -0.3/log(cos(rho/2));
2567 if (object->exponent > 128.0) {
2568 object->exponent = 128.0;
2570 object->cutoff = pLight->Phi*90/M_PI;
2576 FIXME("Unrecognized light type %d\n", pLight->Type);
2579 /* Update the live definitions if the light is currently assigned a glIndex */
2580 if (object->glIndex != -1) {
2581 setup_light(iface, object->glIndex, object);
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2587 PLIGHTINFOEL *lightInfo = NULL;
2588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2591 /* Locate the light in the live lights */
2592 lightInfo = This->stateBlock->lights;
2593 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2595 if (lightInfo == NULL) {
2596 TRACE("Light information requested but light not defined\n");
2597 return WINED3DERR_INVALIDCALL;
2600 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2605 * Get / Set Light Enable
2606 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2609 PLIGHTINFOEL *lightInfo = NULL;
2610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2613 /* Tests show true = 128...not clear why */
2615 Enable = Enable? 128: 0;
2617 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2618 if (This->isRecordingState) {
2619 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2620 if (NULL == lightInfo) {
2621 return WINED3DERR_OUTOFVIDEOMEMORY;
2623 lightInfo->OriginalIndex = Index;
2624 lightInfo->glIndex = -1;
2625 lightInfo->enabledChanged = TRUE;
2626 lightInfo->lightEnabled = Enable;
2628 /* Add to the END of the chain of lights changes to be replayed */
2629 if (This->updateStateBlock->lights == NULL) {
2630 This->updateStateBlock->lights = lightInfo;
2632 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2633 while (temp->next != NULL) temp=temp->next;
2634 temp->next = lightInfo;
2636 TRACE("Recording... not performing anything more\n");
2640 /* Not recording... So, locate the light in the live lights */
2641 lightInfo = This->stateBlock->lights;
2642 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2644 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2645 if (lightInfo == NULL) {
2647 TRACE("Light enabled requested but light not defined, so defining one!\n");
2648 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2650 /* Search for it again! Should be fairly quick as near head of list */
2651 lightInfo = This->stateBlock->lights;
2652 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2653 if (lightInfo == NULL) {
2654 FIXME("Adding default lights has failed dismally\n");
2655 return WINED3DERR_INVALIDCALL;
2659 /* OK, we now have a light... */
2662 /* If we are disabling it, check it was enabled, and
2663 still only do something if it has assigned a glIndex (which it should have!) */
2664 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2665 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2667 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2668 checkGLcall("glDisable GL_LIGHT0+Index");
2671 TRACE("Nothing to do as light was not enabled\n");
2673 lightInfo->lightEnabled = Enable;
2676 /* We are enabling it. If it is enabled, it's really simple */
2677 if (lightInfo->lightEnabled) {
2679 TRACE("Nothing to do as light was enabled\n");
2681 /* If it already has a glIndex, it's still simple */
2682 } else if (lightInfo->glIndex != -1) {
2683 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2684 lightInfo->lightEnabled = Enable;
2686 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2687 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2690 /* Otherwise got to find space - lights are ordered gl indexes first */
2692 PLIGHTINFOEL *bsf = NULL;
2693 PLIGHTINFOEL *pos = This->stateBlock->lights;
2694 PLIGHTINFOEL *prev = NULL;
2698 /* Try to minimize changes as much as possible */
2699 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2701 /* Try to remember which index can be replaced if necessary */
2702 if (bsf==NULL && !pos->lightEnabled) {
2703 /* Found a light we can replace, save as best replacement */
2707 /* Step to next space */
2713 /* If we have too many active lights, fail the call */
2714 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2715 FIXME("Program requests too many concurrent lights\n");
2716 return WINED3DERR_INVALIDCALL;
2718 /* If we have allocated all lights, but not all are enabled,
2719 reuse one which is not enabled */
2720 } else if (Index == This->maxConcurrentLights) {
2721 /* use bsf - Simply swap the new light and the BSF one */
2722 PLIGHTINFOEL *bsfNext = bsf->next;
2723 PLIGHTINFOEL *bsfPrev = bsf->prev;
2726 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2727 if (bsf->prev != NULL) {
2728 bsf->prev->next = lightInfo;
2730 This->stateBlock->lights = lightInfo;
2733 /* If not side by side, lots of chains to update */
2734 if (bsf->next != lightInfo) {
2735 lightInfo->prev->next = bsf;
2736 bsf->next->prev = lightInfo;
2737 bsf->next = lightInfo->next;
2738 bsf->prev = lightInfo->prev;
2739 lightInfo->next = bsfNext;
2740 lightInfo->prev = bsfPrev;
2744 bsf->prev = lightInfo;
2745 bsf->next = lightInfo->next;
2746 lightInfo->next = bsf;
2747 lightInfo->prev = bsfPrev;
2752 glIndex = bsf->glIndex;
2754 lightInfo->glIndex = glIndex;
2755 lightInfo->lightEnabled = Enable;
2757 /* Finally set up the light in gl itself */
2758 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2760 setup_light(iface, glIndex, lightInfo);
2761 glEnable(GL_LIGHT0 + glIndex);
2762 checkGLcall("glEnable GL_LIGHT0 new setup");
2765 /* If we reached the end of the allocated lights, with space in the
2766 gl lights, setup a new light */
2767 } else if (pos->glIndex == -1) {
2769 /* We reached the end of the allocated gl lights, so already
2770 know the index of the next one! */
2772 lightInfo->glIndex = glIndex;
2773 lightInfo->lightEnabled = Enable;
2775 /* In an ideal world, it's already in the right place */
2776 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2777 /* No need to move it */
2779 /* Remove this light from the list */
2780 lightInfo->prev->next = lightInfo->next;
2781 if (lightInfo->next != NULL) {
2782 lightInfo->next->prev = lightInfo->prev;
2785 /* Add in at appropriate place (inbetween prev and pos) */
2786 lightInfo->prev = prev;
2787 lightInfo->next = pos;
2789 This->stateBlock->lights = lightInfo;
2791 prev->next = lightInfo;
2794 pos->prev = lightInfo;
2798 /* Finally set up the light in gl itself */
2799 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
2801 setup_light(iface, glIndex, lightInfo);
2802 glEnable(GL_LIGHT0 + glIndex);
2803 checkGLcall("glEnable GL_LIGHT0 new setup");
2812 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2814 PLIGHTINFOEL *lightInfo = NULL;
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2816 TRACE("(%p) : for idx(%d)\n", This, Index);
2818 /* Locate the light in the live lights */
2819 lightInfo = This->stateBlock->lights;
2820 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2822 if (lightInfo == NULL) {
2823 TRACE("Light enabled state requested but light not defined\n");
2824 return WINED3DERR_INVALIDCALL;
2826 *pEnable = lightInfo->lightEnabled;
2831 * Get / Set Clip Planes
2833 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2837 /* Validate Index */
2838 if (Index >= GL_LIMITS(clipplanes)) {
2839 TRACE("Application has requested clipplane this device doesn't support\n");
2840 return WINED3DERR_INVALIDCALL;
2843 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2844 This->updateStateBlock->set.clipplane[Index] = TRUE;
2845 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2846 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2847 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2848 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2850 /* Handle recording of state blocks */
2851 if (This->isRecordingState) {
2852 TRACE("Recording... not performing anything\n");
2860 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2861 glMatrixMode(GL_MODELVIEW);
2863 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2865 TRACE("Clipplane [%f,%f,%f,%f]\n",
2866 This->updateStateBlock->clipplane[Index][0],
2867 This->updateStateBlock->clipplane[Index][1],
2868 This->updateStateBlock->clipplane[Index][2],
2869 This->updateStateBlock->clipplane[Index][3]);
2870 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2871 checkGLcall("glClipPlane");
2879 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 TRACE("(%p) : for idx %d\n", This, Index);
2883 /* Validate Index */
2884 if (Index >= GL_LIMITS(clipplanes)) {
2885 TRACE("Application has requested clipplane this device doesn't support\n");
2886 return WINED3DERR_INVALIDCALL;
2889 pPlane[0] = This->stateBlock->clipplane[Index][0];
2890 pPlane[1] = This->stateBlock->clipplane[Index][1];
2891 pPlane[2] = This->stateBlock->clipplane[Index][2];
2892 pPlane[3] = This->stateBlock->clipplane[Index][3];
2897 * Get / Set Clip Plane Status
2898 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 FIXME("(%p) : stub\n", This);
2903 if (NULL == pClipStatus) {
2904 return WINED3DERR_INVALIDCALL;
2906 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2907 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2911 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2913 FIXME("(%p) : stub\n", This);
2914 if (NULL == pClipStatus) {
2915 return WINED3DERR_INVALIDCALL;
2917 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2918 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2923 * Get / Set Material
2925 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 This->updateStateBlock->changed.material = TRUE;
2929 This->updateStateBlock->set.material = TRUE;
2930 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2932 /* Handle recording of state blocks */
2933 if (This->isRecordingState) {
2934 TRACE("Recording... not performing anything\n");
2939 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2940 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2941 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2942 pMaterial->Ambient.b, pMaterial->Ambient.a);
2943 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2944 pMaterial->Specular.b, pMaterial->Specular.a);
2945 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2946 pMaterial->Emissive.b, pMaterial->Emissive.a);
2947 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2949 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2950 checkGLcall("glMaterialfv(GL_AMBIENT)");
2951 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2952 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2954 /* Only change material color if specular is enabled, otherwise it is set to black */
2955 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2956 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2957 checkGLcall("glMaterialfv(GL_SPECULAR");
2959 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2960 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2961 checkGLcall("glMaterialfv(GL_SPECULAR");
2963 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2964 checkGLcall("glMaterialfv(GL_EMISSION)");
2965 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2966 checkGLcall("glMaterialf(GL_SHININESS");
2972 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2975 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2976 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2977 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2978 pMaterial->Ambient.b, pMaterial->Ambient.a);
2979 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2980 pMaterial->Specular.b, pMaterial->Specular.a);
2981 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2982 pMaterial->Emissive.b, pMaterial->Emissive.a);
2983 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2991 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2992 UINT BaseVertexIndex) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2994 IWineD3DIndexBuffer *oldIdxs;
2995 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2997 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2998 oldIdxs = This->updateStateBlock->pIndexData;
3000 This->updateStateBlock->changed.indices = TRUE;
3001 This->updateStateBlock->set.indices = TRUE;
3002 This->updateStateBlock->pIndexData = pIndexData;
3003 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3005 /* Handle recording of state blocks */
3006 if (This->isRecordingState) {
3007 TRACE("Recording... not performing anything\n");
3011 if (NULL != pIndexData) {
3012 IWineD3DIndexBuffer_AddRef(pIndexData);
3014 if (NULL != oldIdxs) {
3015 IWineD3DIndexBuffer_Release(oldIdxs);
3018 /* So far only the base vertex index is tracked */
3019 if(BaseVertexIndex != oldBaseIndex) {
3020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3025 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3028 *ppIndexData = This->stateBlock->pIndexData;
3030 /* up ref count on ppindexdata */
3032 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3033 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3034 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3036 TRACE("(%p) No index data set\n", This);
3038 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3043 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3044 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p)->(%d)\n", This, BaseIndex);
3048 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3049 TRACE("Application is setting the old value over, nothing to do\n");
3053 This->updateStateBlock->baseVertexIndex = BaseIndex;
3055 if (This->isRecordingState) {
3056 TRACE("Recording... not performing anything\n");
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3064 * Get / Set Viewports
3066 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 TRACE("(%p)\n", This);
3070 This->updateStateBlock->changed.viewport = TRUE;
3071 This->updateStateBlock->set.viewport = TRUE;
3072 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3074 /* Handle recording of state blocks */
3075 if (This->isRecordingState) {
3076 TRACE("Recording... not performing anything\n");
3079 This->viewport_changed = TRUE;
3083 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3084 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3086 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3087 checkGLcall("glDepthRange");
3088 /* Note: GL requires lower left, DirectX supplies upper left */
3089 /* TODO: replace usage of renderTarget with context management */
3090 glViewport(pViewport->X,
3091 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3092 pViewport->Width, pViewport->Height);
3094 checkGLcall("glViewport");
3098 /* Todo: move the gl code too */
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 TRACE("(%p)\n", This);
3107 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3112 * Get / Set Render States
3113 * TODO: Verify against dx9 definitions
3115 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 DWORD oldValue = This->stateBlock->renderState[State];
3120 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3122 This->updateStateBlock->changed.renderState[State] = TRUE;
3123 This->updateStateBlock->set.renderState[State] = TRUE;
3124 This->updateStateBlock->renderState[State] = Value;
3126 /* Handle recording of state blocks */
3127 if (This->isRecordingState) {
3128 TRACE("Recording... not performing anything\n");
3132 /* Compared here and not before the assignment to allow proper stateblock recording */
3133 if(Value == oldValue) {
3134 TRACE("Application is setting the old value over, nothing to do\n");
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3142 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3145 *pValue = This->stateBlock->renderState[State];
3150 * Get / Set Sampler States
3151 * TODO: Verify against dx9 definitions
3154 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3159 * SetSampler is designed to allow for more than the standard up to 8 textures
3160 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3161 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3163 * http://developer.nvidia.com/object/General_FAQ.html#t6
3165 * There are two new settings for GForce
3167 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3168 * and the texture one:
3169 * GL_MAX_TEXTURE_COORDS_ARB.
3170 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3172 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
3173 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3174 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3175 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3176 return WINED3DERR_INVALIDCALL;
3179 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3180 debug_d3dsamplerstate(Type), Type, Value);
3181 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3182 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3183 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3185 /* Handle recording of state blocks */
3186 if (This->isRecordingState) {
3187 TRACE("Recording... not performing anything\n");
3191 if(oldValue == Value) {
3192 TRACE("Application is setting the old value over, nothing to do\n");
3196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3201 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 /** TODO: check that sampler is in range **/
3204 *Value = This->stateBlock->samplerState[Sampler][Type];
3205 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3210 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3215 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3216 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3217 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3219 winHeight = windowRect.bottom - windowRect.top;
3220 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3221 pRect->right - pRect->left, pRect->bottom - pRect->top);
3223 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3224 checkGLcall("glScissor");
3230 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 GLint scissorBox[4];
3235 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3236 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3237 pRect->left = scissorBox[0];
3238 pRect->top = scissorBox[1];
3239 pRect->right = scissorBox[0] + scissorBox[2];
3240 pRect->bottom = scissorBox[1] + scissorBox[3];
3241 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3246 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3248 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3250 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3252 This->updateStateBlock->vertexDecl = pDecl;
3253 This->updateStateBlock->changed.vertexDecl = TRUE;
3254 This->updateStateBlock->set.vertexDecl = TRUE;
3256 if (This->isRecordingState) {
3257 TRACE("Recording... not performing anything\n");
3260 if (NULL != pDecl) {
3261 IWineD3DVertexDeclaration_AddRef(pDecl);
3263 if (NULL != oldDecl) {
3264 IWineD3DVertexDeclaration_Release(oldDecl);
3266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3270 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3275 *ppDecl = This->stateBlock->vertexDecl;
3276 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3280 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3284 This->updateStateBlock->vertexShader = pShader;
3285 This->updateStateBlock->changed.vertexShader = TRUE;
3286 This->updateStateBlock->set.vertexShader = TRUE;
3288 if (This->isRecordingState) {
3289 TRACE("Recording... not performing anything\n");
3292 if (NULL != pShader) {
3293 IWineD3DVertexShader_AddRef(pShader);
3295 if (NULL != oldShader) {
3296 IWineD3DVertexShader_Release(oldShader);
3299 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3306 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 if (NULL == ppShader) {
3310 return WINED3DERR_INVALIDCALL;
3312 *ppShader = This->stateBlock->vertexShader;
3313 if( NULL != *ppShader)
3314 IWineD3DVertexShader_AddRef(*ppShader);
3316 TRACE("(%p) : returning %p\n", This, *ppShader);
3320 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3321 IWineD3DDevice *iface,
3323 CONST BOOL *srcData,
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 int i, cnt = min(count, MAX_CONST_B - start);
3329 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3330 iface, srcData, start, count);
3332 if (srcData == NULL || cnt < 0)
3333 return WINED3DERR_INVALIDCALL;
3335 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3336 for (i = 0; i < cnt; i++)
3337 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3339 for (i = start; i < cnt + start; ++i) {
3340 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3341 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3347 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3348 IWineD3DDevice *iface,
3353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 int cnt = min(count, MAX_CONST_B - start);
3356 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3357 iface, dstData, start, count);
3359 if (dstData == NULL || cnt < 0)
3360 return WINED3DERR_INVALIDCALL;
3362 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3366 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3367 IWineD3DDevice *iface,
3372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3373 int i, cnt = min(count, MAX_CONST_I - start);
3375 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3376 iface, srcData, start, count);
3378 if (srcData == NULL || cnt < 0)
3379 return WINED3DERR_INVALIDCALL;
3381 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3382 for (i = 0; i < cnt; i++)
3383 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3384 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3386 for (i = start; i < cnt + start; ++i) {
3387 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3388 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3395 IWineD3DDevice *iface,
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 int cnt = min(count, MAX_CONST_I - start);
3403 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3404 iface, dstData, start, count);
3406 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3407 return WINED3DERR_INVALIDCALL;
3409 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3413 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3414 IWineD3DDevice *iface,
3416 CONST float *srcData,
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3422 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3423 iface, srcData, start, count);
3425 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3426 return WINED3DERR_INVALIDCALL;
3428 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3429 for (i = 0; i < cnt; i++)
3430 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3431 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3433 for (i = start; i < cnt + start; ++i) {
3434 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3435 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3437 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3438 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3440 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3446 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3447 IWineD3DDevice *iface,
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3455 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3456 iface, dstData, start, count);
3458 if (dstData == NULL || cnt < 0)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3465 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3467 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3472 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3474 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3475 * it is never called.
3478 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3479 * that would be really messy and require shader recompilation
3480 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3481 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3482 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3483 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3485 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3486 if(This->oneToOneTexUnitMap) {
3487 TRACE("Not touching 1:1 map\n");
3490 TRACE("Restoring 1:1 texture unit mapping\n");
3491 /* Restore a 1:1 mapping */
3492 for(i = 0; i < MAX_SAMPLERS; i++) {
3493 if(This->texUnitMap[i] != i) {
3494 This->texUnitMap[i] = i;
3495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3496 markTextureStagesDirty(This, i);
3499 This->oneToOneTexUnitMap = TRUE;
3502 /* No pixel shader, and we do not have enought texture units available. Try to skip NULL textures
3503 * First, see if we can succeed at all
3506 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3507 if(This->stateBlock->textures[i] == NULL) tex++;
3510 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3511 FIXME("Too many bound textures to support the combiner settings\n");
3515 /* Now work out the mapping */
3517 This->oneToOneTexUnitMap = FALSE;
3518 WARN("Non 1:1 mapping UNTESTED!\n");
3519 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3520 /* Skip NULL textures */
3521 if (!This->stateBlock->textures[i]) {
3522 /* Map to -1, so the check below doesn't fail if a non-NULL
3523 * texture is set on this stage */
3524 TRACE("Mapping texture stage %d to -1\n", i);
3525 This->texUnitMap[i] = -1;
3530 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3531 if(This->texUnitMap[i] != tex) {
3532 This->texUnitMap[i] = tex;
3533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3534 markTextureStagesDirty(This, i);
3542 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3545 This->updateStateBlock->pixelShader = pShader;
3546 This->updateStateBlock->changed.pixelShader = TRUE;
3547 This->updateStateBlock->set.pixelShader = TRUE;
3549 /* Handle recording of state blocks */
3550 if (This->isRecordingState) {
3551 TRACE("Recording... not performing anything\n");
3554 if (NULL != pShader) {
3555 IWineD3DPixelShader_AddRef(pShader);
3557 if (NULL != oldShader) {
3558 IWineD3DPixelShader_Release(oldShader);
3561 if (This->isRecordingState) {
3562 TRACE("Recording... not performing anything\n");
3566 if(pShader == oldShader) {
3567 TRACE("App is setting the old pixel shader over, nothing to do\n");
3571 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3574 /* Rebuild the texture unit mapping if nvrc's are supported */
3575 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3576 IWineD3DDeviceImpl_FindTexUnitMap(This);
3582 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 if (NULL == ppShader) {
3586 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3587 return WINED3DERR_INVALIDCALL;
3590 *ppShader = This->stateBlock->pixelShader;
3591 if (NULL != *ppShader) {
3592 IWineD3DPixelShader_AddRef(*ppShader);
3594 TRACE("(%p) : returning %p\n", This, *ppShader);
3598 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3599 IWineD3DDevice *iface,
3601 CONST BOOL *srcData,
3604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3605 int i, cnt = min(count, MAX_CONST_B - start);
3607 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3608 iface, srcData, start, count);
3610 if (srcData == NULL || cnt < 0)
3611 return WINED3DERR_INVALIDCALL;
3613 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3614 for (i = 0; i < cnt; i++)
3615 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3617 for (i = start; i < cnt + start; ++i) {
3618 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3619 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3625 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3626 IWineD3DDevice *iface,
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3632 int cnt = min(count, MAX_CONST_B - start);
3634 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3635 iface, dstData, start, count);
3637 if (dstData == NULL || cnt < 0)
3638 return WINED3DERR_INVALIDCALL;
3640 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3644 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3645 IWineD3DDevice *iface,
3650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3651 int i, cnt = min(count, MAX_CONST_I - start);
3653 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3654 iface, srcData, start, count);
3656 if (srcData == NULL || cnt < 0)
3657 return WINED3DERR_INVALIDCALL;
3659 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3660 for (i = 0; i < cnt; i++)
3661 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3662 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3664 for (i = start; i < cnt + start; ++i) {
3665 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3666 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3672 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3673 IWineD3DDevice *iface,
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 int cnt = min(count, MAX_CONST_I - start);
3681 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3682 iface, dstData, start, count);
3684 if (dstData == NULL || cnt < 0)
3685 return WINED3DERR_INVALIDCALL;
3687 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3691 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3692 IWineD3DDevice *iface,
3694 CONST float *srcData,
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3700 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3701 iface, srcData, start, count);
3703 if (srcData == NULL || cnt < 0)
3704 return WINED3DERR_INVALIDCALL;
3706 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3707 for (i = 0; i < cnt; i++)
3708 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3709 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3711 for (i = start; i < cnt + start; ++i) {
3712 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3713 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3715 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3716 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3718 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3724 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3725 IWineD3DDevice *iface,
3730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3731 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3733 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3734 iface, dstData, start, count);
3736 if (dstData == NULL || cnt < 0)
3737 return WINED3DERR_INVALIDCALL;
3739 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3743 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3745 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3746 char *dest_ptr, *dest_conv = NULL;
3748 DWORD DestFVF = dest->fvf;
3750 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3754 if (SrcFVF & WINED3DFVF_NORMAL) {
3755 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3758 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3759 ERR("Source has no position mask\n");
3760 return WINED3DERR_INVALIDCALL;
3763 /* We might access VBOs from this code, so hold the lock */
3766 if (dest->resource.allocatedMemory == NULL) {
3767 /* This may happen if we do direct locking into a vbo. Unlikely,
3768 * but theoretically possible(ddraw processvertices test)
3770 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3771 if(!dest->resource.allocatedMemory) {
3773 ERR("Out of memory\n");
3774 return E_OUTOFMEMORY;
3778 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3779 checkGLcall("glBindBufferARB");
3780 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3782 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3784 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3785 checkGLcall("glUnmapBufferARB");
3789 /* Get a pointer into the destination vbo(create one if none exists) and
3790 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3792 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3797 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3798 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3800 ERR("glMapBuffer failed\n");
3801 /* Continue without storing converted vertices */
3806 * a) WINED3DRS_CLIPPING is enabled
3807 * b) WINED3DVOP_CLIP is passed
3809 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3810 static BOOL warned = FALSE;
3812 * The clipping code is not quite correct. Some things need
3813 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3814 * so disable clipping for now.
3815 * (The graphics in Half-Life are broken, and my processvertices
3816 * test crashes with IDirect3DDevice3)
3822 FIXME("Clipping is broken and disabled for now\n");
3824 } else doClip = FALSE;
3825 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3827 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3830 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3833 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3834 WINED3DTS_PROJECTION,
3836 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3837 WINED3DTS_WORLDMATRIX(0),
3840 TRACE("View mat:\n");
3841 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); \
3842 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); \
3843 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); \
3844 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); \
3846 TRACE("Proj mat:\n");
3847 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); \
3848 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); \
3849 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); \
3850 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); \
3852 TRACE("World mat:\n");
3853 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); \
3854 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); \
3855 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); \
3856 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); \
3858 /* Get the viewport */
3859 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3860 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3861 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3863 multiply_matrix(&mat,&view_mat,&world_mat);
3864 multiply_matrix(&mat,&proj_mat,&mat);
3866 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3868 for (i = 0; i < dwCount; i+= 1) {
3869 unsigned int tex_index;
3871 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3872 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3873 /* The position first */
3875 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3877 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3879 /* Multiplication with world, view and projection matrix */
3880 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);
3881 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);
3882 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);
3883 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);
3885 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3887 /* WARNING: The following things are taken from d3d7 and were not yet checked
3888 * against d3d8 or d3d9!
3891 /* Clipping conditions: From
3892 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3894 * A vertex is clipped if it does not match the following requirements
3898 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3900 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3901 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3906 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3907 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3910 /* "Normal" viewport transformation (not clipped)
3911 * 1) The values are divided by rhw
3912 * 2) The y axis is negative, so multiply it with -1
3913 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3914 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3915 * 4) Multiply x with Width/2 and add Width/2
3916 * 5) The same for the height
3917 * 6) Add the viewpoint X and Y to the 2D coordinates and
3918 * The minimum Z value to z
3919 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3921 * Well, basically it's simply a linear transformation into viewport
3933 z *= vp.MaxZ - vp.MinZ;
3935 x += vp.Width / 2 + vp.X;
3936 y += vp.Height / 2 + vp.Y;
3941 /* That vertex got clipped
3942 * Contrary to OpenGL it is not dropped completely, it just
3943 * undergoes a different calculation.
3945 TRACE("Vertex got clipped\n");
3952 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3953 * outside of the main vertex buffer memory. That needs some more
3958 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3961 ( (float *) dest_ptr)[0] = x;
3962 ( (float *) dest_ptr)[1] = y;
3963 ( (float *) dest_ptr)[2] = z;
3964 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3966 dest_ptr += 3 * sizeof(float);
3968 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3969 dest_ptr += sizeof(float);
3974 ( (float *) dest_conv)[0] = x * w;
3975 ( (float *) dest_conv)[1] = y * w;
3976 ( (float *) dest_conv)[2] = z * w;
3977 ( (float *) dest_conv)[3] = w;
3979 dest_conv += 3 * sizeof(float);
3981 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3982 dest_conv += sizeof(float);
3986 if (DestFVF & WINED3DFVF_PSIZE) {
3987 dest_ptr += sizeof(DWORD);
3988 if(dest_conv) dest_conv += sizeof(DWORD);
3990 if (DestFVF & WINED3DFVF_NORMAL) {
3992 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3993 /* AFAIK this should go into the lighting information */
3994 FIXME("Didn't expect the destination to have a normal\n");
3995 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3997 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4001 if (DestFVF & WINED3DFVF_DIFFUSE) {
4003 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4005 static BOOL warned = FALSE;
4008 ERR("No diffuse color in source, but destination has one\n");
4012 *( (DWORD *) dest_ptr) = 0xffffffff;
4013 dest_ptr += sizeof(DWORD);
4016 *( (DWORD *) dest_conv) = 0xffffffff;
4017 dest_conv += sizeof(DWORD);
4021 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4023 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4024 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4025 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4026 dest_conv += sizeof(DWORD);
4031 if (DestFVF & WINED3DFVF_SPECULAR) {
4032 /* What's the color value in the feedback buffer? */
4034 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4036 static BOOL warned = FALSE;
4039 ERR("No specular color in source, but destination has one\n");
4043 *( (DWORD *) dest_ptr) = 0xFF000000;
4044 dest_ptr += sizeof(DWORD);
4047 *( (DWORD *) dest_conv) = 0xFF000000;
4048 dest_conv += sizeof(DWORD);
4052 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4054 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4055 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4056 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4057 dest_conv += sizeof(DWORD);
4062 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4064 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4065 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4067 ERR("No source texture, but destination requests one\n");
4068 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4069 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4072 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4074 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4081 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4082 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4089 #undef copy_and_next
4091 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4093 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4094 WineDirect3DVertexStridedData strided;
4095 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4098 WARN("NULL source vertex buffer\n");
4099 return WINED3DERR_INVALIDCALL;
4101 /* We don't need the source vbo because this buffer is only used as
4102 * a source for ProcessVertices. Avoid wasting resources by converting the
4103 * buffer and loading the VBO
4106 TRACE("Releasing the source vbo, it won't be needed\n");
4108 if(!SrcImpl->resource.allocatedMemory) {
4109 /* Rescue the data from the buffer */
4111 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4112 if(!SrcImpl->resource.allocatedMemory) {
4113 ERR("Out of memory\n");
4114 return E_OUTOFMEMORY;
4118 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4119 checkGLcall("glBindBufferARB");
4121 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4123 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4126 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4127 checkGLcall("glUnmapBufferARB");
4132 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4133 checkGLcall("glBindBufferARB");
4134 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4135 checkGLcall("glDeleteBuffersARB");
4141 memset(&strided, 0, sizeof(strided));
4142 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4144 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4148 * Get / Set Texture Stage States
4149 * TODO: Verify against dx9 definitions
4151 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4155 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4157 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4159 /* Reject invalid texture units */
4160 if (Stage >= GL_LIMITS(texture_stages)) {
4161 TRACE("Attempt to access invalid texture rejected\n");
4162 return WINED3DERR_INVALIDCALL;
4165 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4166 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4167 This->updateStateBlock->textureState[Stage][Type] = Value;
4169 if (This->isRecordingState) {
4170 TRACE("Recording... not performing anything\n");
4174 /* Checked after the assignments to allow proper stateblock recording */
4175 if(oldValue == Value) {
4176 TRACE("App is setting the old value over, nothing to do\n");
4180 if(Stage > This->stateBlock->lowest_disabled_stage &&
4181 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4182 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4183 * Changes in other states are important on disabled stages too
4188 if(Type == WINED3DTSS_COLOROP) {
4191 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4192 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4193 * they have to be disabled
4195 * The current stage is dirtified below.
4197 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4198 TRACE("Additionally dirtifying stage %d\n", i);
4199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4201 This->stateBlock->lowest_disabled_stage = Stage;
4202 TRACE("New lowest disabled: %d\n", Stage);
4203 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4204 /* Previously disabled stage enabled. Stages above it may need enabling
4205 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4206 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4208 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4211 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4212 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4215 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4218 This->stateBlock->lowest_disabled_stage = i;
4219 TRACE("New lowest disabled: %d\n", i);
4221 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4222 /* TODO: Built a stage -> texture unit mapping for register combiners */
4226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4228 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4229 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4230 * will call FindTexUnitMap too.
4232 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4233 IWineD3DDeviceImpl_FindTexUnitMap(This);
4238 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4240 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4241 *pValue = This->updateStateBlock->textureState[Stage][Type];
4248 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4251 IWineD3DBaseTexture *oldTexture;
4253 oldTexture = This->updateStateBlock->textures[Stage];
4254 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4256 #if 0 /* TODO: check so vertex textures */
4257 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4258 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4263 /* Reject invalid texture units */
4264 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4265 WARN("Attempt to access invalid texture rejected\n");
4266 return WINED3DERR_INVALIDCALL;
4269 if(pTexture != NULL) {
4270 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4272 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4273 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4274 return WINED3DERR_INVALIDCALL;
4276 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4279 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4280 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4282 This->updateStateBlock->set.textures[Stage] = TRUE;
4283 This->updateStateBlock->changed.textures[Stage] = TRUE;
4284 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4285 This->updateStateBlock->textures[Stage] = pTexture;
4287 /* Handle recording of state blocks */
4288 if (This->isRecordingState) {
4289 TRACE("Recording... not performing anything\n");
4293 if(oldTexture == pTexture) {
4294 TRACE("App is setting the same texture again, nothing to do\n");
4298 /** NOTE: MSDN says that setTexture increases the reference count,
4299 * and the the application nust set the texture back to null (or have a leaky application),
4300 * This means we should pass the refcount up to the parent
4301 *******************************/
4302 if (NULL != This->updateStateBlock->textures[Stage]) {
4303 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4304 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4306 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4307 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4308 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4309 * so the COLOROP and ALPHAOP have to be dirtified.
4311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4314 if(bindCount == 1) {
4315 new->baseTexture.sampler = Stage;
4317 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4321 if (NULL != oldTexture) {
4322 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4323 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4325 IWineD3DBaseTexture_Release(oldTexture);
4326 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4331 if(bindCount && old->baseTexture.sampler == Stage) {
4333 /* Have to do a search for the other sampler(s) where the texture is bound to
4334 * Shouldn't happen as long as apps bind a texture only to one stage
4336 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4337 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4338 if(This->updateStateBlock->textures[i] == oldTexture) {
4339 old->baseTexture.sampler = i;
4346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4348 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4349 * pixel shader is used
4351 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4352 IWineD3DDeviceImpl_FindTexUnitMap(This);
4358 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4360 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4362 /* Reject invalid texture units */
4363 if (Stage >= GL_LIMITS(sampler_stages)) {
4364 TRACE("Attempt to access invalid texture rejected\n");
4365 return WINED3DERR_INVALIDCALL;
4367 *ppTexture=This->stateBlock->textures[Stage];
4369 IWineD3DBaseTexture_AddRef(*ppTexture);
4377 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4378 IWineD3DSurface **ppBackBuffer) {
4379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4380 IWineD3DSwapChain *swapChain;
4383 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4385 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4386 if (hr == WINED3D_OK) {
4387 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4388 IWineD3DSwapChain_Release(swapChain);
4390 *ppBackBuffer = NULL;
4395 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4397 WARN("(%p) : stub, calling idirect3d for now\n", This);
4398 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4401 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4403 IWineD3DSwapChain *swapChain;
4406 if(iSwapChain > 0) {
4407 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4408 if (hr == WINED3D_OK) {
4409 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4410 IWineD3DSwapChain_Release(swapChain);
4412 FIXME("(%p) Error getting display mode\n", This);
4415 /* Don't read the real display mode,
4416 but return the stored mode instead. X11 can't change the color
4417 depth, and some apps are pretty angry if they SetDisplayMode from
4418 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4420 Also don't relay to the swapchain because with ddraw it's possible
4421 that there isn't a swapchain at all */
4422 pMode->Width = This->ddraw_width;
4423 pMode->Height = This->ddraw_height;
4424 pMode->Format = This->ddraw_format;
4425 pMode->RefreshRate = 0;
4432 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4434 TRACE("(%p)->(%p)\n", This, hWnd);
4436 This->ddraw_window = hWnd;
4440 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 TRACE("(%p)->(%p)\n", This, hWnd);
4444 *hWnd = This->ddraw_window;
4449 * Stateblock related functions
4452 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4454 IWineD3DStateBlockImpl *object;
4455 HRESULT temp_result;
4457 TRACE("(%p)\n", This);
4459 if (This->isRecordingState) {
4460 return WINED3DERR_INVALIDCALL;
4463 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4464 if (NULL == object ) {
4465 FIXME("(%p)Error allocating memory for stateblock\n", This);
4466 return E_OUTOFMEMORY;
4468 TRACE("(%p) created object %p\n", This, object);
4469 object->wineD3DDevice= This;
4470 /** FIXME: object->parent = parent; **/
4471 object->parent = NULL;
4472 object->blockType = WINED3DSBT_ALL;
4474 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4476 temp_result = allocate_shader_constants(object);
4477 if (WINED3D_OK != temp_result)
4480 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4481 This->updateStateBlock = object;
4482 This->isRecordingState = TRUE;
4484 TRACE("(%p) recording stateblock %p\n",This , object);
4488 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4491 if (!This->isRecordingState) {
4492 FIXME("(%p) not recording! returning error\n", This);
4493 *ppStateBlock = NULL;
4494 return WINED3DERR_INVALIDCALL;
4497 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4498 This->isRecordingState = FALSE;
4499 This->updateStateBlock = This->stateBlock;
4500 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4501 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4502 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4507 * Scene related functions
4509 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4510 /* At the moment we have no need for any functionality at the beginning
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4513 TRACE("(%p) : stub\n", This);
4517 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 TRACE("(%p)\n", This);
4521 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4523 checkGLcall("glFlush");
4525 TRACE("End Scene\n");
4526 /* If we're using FBOs this isn't needed */
4527 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4529 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4530 IUnknown *targetContainer = NULL;
4531 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4532 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4533 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4534 /** always dirtify for now. we must find a better way to see that surface have been modified
4535 (Modifications should will only occur via draw-primitive, but we do need better locking
4536 switching to render-to-texture should remove the overhead though.
4538 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4539 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4540 IWineD3DSurface_PreLoad(This->render_targets[0]);
4541 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4542 IUnknown_Release(targetContainer);
4545 This->sceneEnded = TRUE;
4550 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4551 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4552 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4554 IWineD3DSwapChain *swapChain = NULL;
4556 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4558 TRACE("(%p) Presenting the frame\n", This);
4560 for(i = 0 ; i < swapchains ; i ++) {
4562 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4563 TRACE("presentinng chain %d, %p\n", i, swapChain);
4564 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4565 IWineD3DSwapChain_Release(swapChain);
4571 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4572 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4576 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4577 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4578 GLbitfield glMask = 0;
4579 GLboolean old_ztest;
4580 GLfloat old_z_clear_value;
4581 GLint old_stencil_clear_value;
4582 GLfloat old_color_clear_value[4];
4584 CONST WINED3DRECT* curRect;
4586 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4587 Count, pRects, Flags, Z, Stencil);
4591 glEnable(GL_SCISSOR_TEST);
4592 checkGLcall("glEnable GL_SCISSOR_TEST");
4594 if (Count > 0 && pRects) {
4600 /* Only set the values up once, as they are not changing */
4601 if (Flags & WINED3DCLEAR_STENCIL) {
4602 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4603 glClearStencil(Stencil);
4604 checkGLcall("glClearStencil");
4605 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4606 glStencilMask(0xFFFFFFFF);
4609 if (Flags & WINED3DCLEAR_ZBUFFER) {
4610 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4611 glDepthMask(GL_TRUE);
4612 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4614 checkGLcall("glClearDepth");
4615 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4618 if (Flags & WINED3DCLEAR_TARGET) {
4619 TRACE("Clearing screen with glClear to color %x\n", Color);
4620 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4621 glClearColor(D3DCOLOR_R(Color),
4625 checkGLcall("glClearColor");
4627 /* Clear ALL colors! */
4628 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4629 glMask = glMask | GL_COLOR_BUFFER_BIT;
4632 /* Now process each rect in turn */
4633 for (i = 0; i < Count || i == 0; i++) {
4636 /* Note gl uses lower left, width/height */
4637 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4638 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4639 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4640 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4641 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4642 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4643 checkGLcall("glScissor");
4645 glScissor(This->stateBlock->viewport.X,
4646 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4647 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4648 This->stateBlock->viewport.Width,
4649 This->stateBlock->viewport.Height);
4650 checkGLcall("glScissor");
4653 /* Clear the selected rectangle (or full screen) */
4655 checkGLcall("glClear");
4657 /* Step to the next rectangle */
4658 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4661 /* Restore the old values (why..?) */
4662 if (Flags & WINED3DCLEAR_STENCIL) {
4663 glClearStencil(old_stencil_clear_value);
4664 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4666 if (Flags & WINED3DCLEAR_ZBUFFER) {
4667 glDepthMask(old_ztest);
4668 glClearDepth(old_z_clear_value);
4670 if (Flags & WINED3DCLEAR_TARGET) {
4671 glClearColor(old_color_clear_value[0],
4672 old_color_clear_value[1],
4673 old_color_clear_value[2],
4674 old_color_clear_value[3]);
4675 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4676 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4677 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4678 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4681 glDisable(GL_SCISSOR_TEST);
4682 checkGLcall("glDisable");
4691 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4692 UINT PrimitiveCount) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 This->stateBlock->streamIsUP = FALSE;
4697 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4698 debug_d3dprimitivetype(PrimitiveType),
4699 StartVertex, PrimitiveCount);
4701 if(StartVertex - This->stateBlock->baseVertexIndex < 0) ERR("Drawing negative\n");
4702 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4703 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex - This->stateBlock->baseVertexIndex, 0/* NumVertices */, -1 /* indxStart */,
4704 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4708 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4709 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4710 WINED3DPRIMITIVETYPE PrimitiveType,
4711 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4715 IWineD3DIndexBuffer *pIB;
4716 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4718 pIB = This->stateBlock->pIndexData;
4719 This->stateBlock->streamIsUP = FALSE;
4721 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4722 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4723 minIndex, NumVertices, startIndex, primCount);
4725 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4726 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4732 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4733 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4738 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4739 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4740 UINT VertexStreamZeroStride) {
4741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4743 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4744 debug_d3dprimitivetype(PrimitiveType),
4745 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4747 /* release the stream source */
4748 if (This->stateBlock->streamSource[0] != NULL) {
4749 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4752 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4753 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4754 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4755 This->stateBlock->streamIsUP = TRUE;
4757 drawPrimitive(iface, PrimitiveType, PrimitiveCount, -This->stateBlock->baseVertexIndex /* start vertex */, 0 /* NumVertices */,
4758 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4760 /* MSDN specifies stream zero settings must be set to NULL */
4761 This->stateBlock->streamStride[0] = 0;
4762 This->stateBlock->streamSource[0] = NULL;
4764 /*stream zero settings set to null at end, as per the msdn */
4768 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4769 UINT MinVertexIndex, UINT NumVertices,
4770 UINT PrimitiveCount, CONST void* pIndexData,
4771 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4772 UINT VertexStreamZeroStride) {
4774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4776 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4777 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4778 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4779 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4781 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4787 /* release the stream and index data */
4788 if (This->stateBlock->streamSource[0] != NULL) {
4789 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4791 if (This->stateBlock->pIndexData) {
4792 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
4795 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4796 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4797 This->stateBlock->streamIsUP = TRUE;
4798 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4800 /* Mark the state dirty until we have nicer tracking */
4801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4802 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4803 This->stateBlock->baseVertexIndex = 0;
4805 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4807 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4808 This->stateBlock->streamSource[0] = NULL;
4809 This->stateBlock->streamStride[0] = 0;
4810 This->stateBlock->pIndexData = NULL;
4815 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4818 /* Mark the state dirty until we have nicer tracking
4819 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4823 This->stateBlock->baseVertexIndex = 0;
4824 This->up_strided = DrawPrimStrideData;
4825 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4826 This->up_strided = NULL;
4829 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4830 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4832 HRESULT hr = WINED3D_OK;
4833 WINED3DRESOURCETYPE sourceType;
4834 WINED3DRESOURCETYPE destinationType;
4837 /* TODO: think about moving the code into IWineD3DBaseTexture */
4839 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4841 /* verify that the source and destination textures aren't NULL */
4842 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4843 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4844 This, pSourceTexture, pDestinationTexture);
4845 hr = WINED3DERR_INVALIDCALL;
4848 if (pSourceTexture == pDestinationTexture) {
4849 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4850 This, pSourceTexture, pDestinationTexture);
4851 hr = WINED3DERR_INVALIDCALL;
4853 /* Verify that the source and destination textures are the same type */
4854 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4855 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4857 if (sourceType != destinationType) {
4858 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4860 hr = WINED3DERR_INVALIDCALL;
4863 /* check that both textures have the identical numbers of levels */
4864 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4865 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4866 hr = WINED3DERR_INVALIDCALL;
4869 if (WINED3D_OK == hr) {
4871 /* Make sure that the destination texture is loaded */
4872 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4874 /* Update every surface level of the texture */
4875 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4877 switch (sourceType) {
4878 case WINED3DRTYPE_TEXTURE:
4880 IWineD3DSurface *srcSurface;
4881 IWineD3DSurface *destSurface;
4883 for (i = 0 ; i < levels ; ++i) {
4884 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4885 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4886 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4887 IWineD3DSurface_Release(srcSurface);
4888 IWineD3DSurface_Release(destSurface);
4889 if (WINED3D_OK != hr) {
4890 WARN("(%p) : Call to update surface failed\n", This);
4896 case WINED3DRTYPE_CUBETEXTURE:
4898 IWineD3DSurface *srcSurface;
4899 IWineD3DSurface *destSurface;
4900 WINED3DCUBEMAP_FACES faceType;
4902 for (i = 0 ; i < levels ; ++i) {
4903 /* Update each cube face */
4904 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4905 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4906 if (WINED3D_OK != hr) {
4907 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4909 TRACE("Got srcSurface %p\n", srcSurface);
4911 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4912 if (WINED3D_OK != hr) {
4913 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4915 TRACE("Got desrSurface %p\n", destSurface);
4917 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4918 IWineD3DSurface_Release(srcSurface);
4919 IWineD3DSurface_Release(destSurface);
4920 if (WINED3D_OK != hr) {
4921 WARN("(%p) : Call to update surface failed\n", This);
4928 #if 0 /* TODO: Add support for volume textures */
4929 case WINED3DRTYPE_VOLUMETEXTURE:
4931 IWineD3DVolume srcVolume = NULL;
4932 IWineD3DSurface destVolume = NULL;
4934 for (i = 0 ; i < levels ; ++i) {
4935 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4936 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4937 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4938 IWineD3DVolume_Release(srcSurface);
4939 IWineD3DVolume_Release(destSurface);
4940 if (WINED3D_OK != hr) {
4941 WARN("(%p) : Call to update volume failed\n", This);
4949 FIXME("(%p) : Unsupported source and destination type\n", This);
4950 hr = WINED3DERR_INVALIDCALL;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
4958 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
4959 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 TRACE("(%p) : stub\n", This);
4965 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
4966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4967 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
4968 * NOTE It may be best to move the code into surface to occomplish this
4969 ****************************************/
4971 WINED3DSURFACE_DESC surfaceDesc;
4972 unsigned int surfaceWidth, surfaceHeight;
4973 glDescriptor *targetGlDescription = NULL;
4974 glDescriptor *surfaceGlDescription = NULL;
4975 IWineD3DSwapChainImpl *container = NULL;
4977 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
4978 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
4979 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
4981 surfaceDesc.Width = &surfaceWidth;
4982 surfaceDesc.Height = &surfaceHeight;
4983 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
4984 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
4986 /* Ok, I may need to setup some kind of active swapchain reference on the device */
4987 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
4989 /* TODO: opengl Context switching for swapchains etc... */
4990 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
4991 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
4992 glReadBuffer(GL_BACK);
4993 vcheckGLcall("glReadBuffer(GL_BACK)");
4994 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
4995 glReadBuffer(GL_FRONT);
4996 vcheckGLcall("glReadBuffer(GL_FRONT)");
4997 } else if (pRenderTarget == This->depthStencilBuffer) {
4998 FIXME("Reading of depthstencil not yet supported\n");
5005 surfaceGlDescription->glFormat,
5006 surfaceGlDescription->glType,
5007 (void *)IWineD3DSurface_GetData(pSurface));
5008 vcheckGLcall("glReadPixels(...)");
5009 if(NULL != container ){
5010 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5013 IWineD3DBaseTexture *container;
5014 GLenum textureDimensions = GL_TEXTURE_2D;
5016 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5017 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5018 IWineD3DBaseTexture_Release(container);
5020 /* TODO: 2D -> Cube surface coppies etc.. */
5021 if (surfaceGlDescription->target != textureDimensions) {
5022 FIXME("(%p) : Texture dimension mismatch\n", This);
5024 glEnable(textureDimensions);
5025 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5026 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5027 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5028 vcheckGLcall("glBindTexture");
5029 glGetTexImage(surfaceGlDescription->target,
5030 surfaceGlDescription->level,
5031 surfaceGlDescription->glFormat,
5032 surfaceGlDescription->glType,
5033 (void *)IWineD3DSurface_GetData(pSurface));
5034 glDisable(textureDimensions);
5035 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5042 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5043 IWineD3DSwapChain *swapChain;
5045 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5046 if(hr == WINED3D_OK) {
5047 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5048 IWineD3DSwapChain_Release(swapChain);
5053 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5055 /* return a sensible default */
5057 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5058 FIXME("(%p) : stub\n", This);
5062 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5065 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5066 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5067 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5068 return WINED3DERR_INVALIDCALL;
5070 for (j = 0; j < 256; ++j) {
5071 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5072 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5073 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5074 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5076 TRACE("(%p) : returning\n", This);
5080 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5084 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5085 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5086 return WINED3DERR_INVALIDCALL;
5088 for (j = 0; j < 256; ++j) {
5089 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5090 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5091 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5092 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5094 TRACE("(%p) : returning\n", This);
5098 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5100 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5101 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5102 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5103 return WINED3DERR_INVALIDCALL;
5105 /*TODO: stateblocks */
5106 This->currentPalette = PaletteNumber;
5107 TRACE("(%p) : returning\n", This);
5111 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5113 if (PaletteNumber == NULL) {
5114 WARN("(%p) : returning Invalid Call\n", This);
5115 return WINED3DERR_INVALIDCALL;
5117 /*TODO: stateblocks */
5118 *PaletteNumber = This->currentPalette;
5119 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5123 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 static BOOL showFixmes = TRUE;
5127 FIXME("(%p) : stub\n", This);
5131 This->softwareVertexProcessing = bSoftware;
5136 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5138 static BOOL showFixmes = TRUE;
5140 FIXME("(%p) : stub\n", This);
5143 return This->softwareVertexProcessing;
5147 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 IWineD3DSwapChain *swapChain;
5152 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5154 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5155 if(hr == WINED3D_OK){
5156 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5157 IWineD3DSwapChain_Release(swapChain);
5159 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5165 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 static BOOL showfixmes = TRUE;
5168 if(nSegments != 0.0f) {
5170 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5177 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5179 static BOOL showfixmes = TRUE;
5181 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5187 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5189 /** TODO: remove casts to IWineD3DSurfaceImpl
5190 * NOTE: move code to surface to accomplish this
5191 ****************************************/
5192 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5193 int srcWidth, srcHeight;
5194 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5195 WINED3DFORMAT destFormat, srcFormat;
5197 int destLeft, destTop;
5198 WINED3DPOOL srcPool, destPool;
5200 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5201 glDescriptor *glDescription = NULL;
5202 GLenum textureDimensions = GL_TEXTURE_2D;
5203 IWineD3DBaseTexture *baseTexture;
5205 WINED3DSURFACE_DESC winedesc;
5207 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5208 memset(&winedesc, 0, sizeof(winedesc));
5209 winedesc.Width = &srcSurfaceWidth;
5210 winedesc.Height = &srcSurfaceHeight;
5211 winedesc.Pool = &srcPool;
5212 winedesc.Format = &srcFormat;
5214 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5216 winedesc.Width = &destSurfaceWidth;
5217 winedesc.Height = &destSurfaceHeight;
5218 winedesc.Pool = &destPool;
5219 winedesc.Format = &destFormat;
5220 winedesc.Size = &destSize;
5222 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5224 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5225 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5226 return WINED3DERR_INVALIDCALL;
5229 if (destFormat == WINED3DFMT_UNKNOWN) {
5230 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5231 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5233 /* Get the update surface description */
5234 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5237 /* Make sure the surface is loaded and up to date */
5238 IWineD3DSurface_PreLoad(pDestinationSurface);
5240 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5244 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5245 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5246 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5247 destLeft = pDestPoint ? pDestPoint->x : 0;
5248 destTop = pDestPoint ? pDestPoint->y : 0;
5251 /* This function doesn't support compressed textures
5252 the pitch is just bytesPerPixel * width */
5253 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5254 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5255 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5256 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5258 /* TODO DXT formats */
5260 if(pSourceRect != NULL && pSourceRect->top != 0){
5261 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5263 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5265 ,glDescription->level
5270 ,glDescription->glFormat
5271 ,glDescription->glType
5272 ,IWineD3DSurface_GetData(pSourceSurface)
5276 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5278 /* need to lock the surface to get the data */
5279 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5282 /* TODO: Cube and volume support */
5284 /* not a whole row so we have to do it a line at a time */
5287 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5288 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5290 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5292 glTexSubImage2D(glDescription->target
5293 ,glDescription->level
5298 ,glDescription->glFormat
5299 ,glDescription->glType
5300 ,data /* could be quicker using */
5305 } else { /* Full width, so just write out the whole texture */
5307 if (WINED3DFMT_DXT1 == destFormat ||
5308 WINED3DFMT_DXT2 == destFormat ||
5309 WINED3DFMT_DXT3 == destFormat ||
5310 WINED3DFMT_DXT4 == destFormat ||
5311 WINED3DFMT_DXT5 == destFormat) {
5312 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5313 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5314 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5315 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5316 } if (destFormat != srcFormat) {
5317 FIXME("Updating mixed format compressed texture is not curretly support\n");
5319 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5320 glDescription->level,
5321 glDescription->glFormatInternal,
5326 IWineD3DSurface_GetData(pSourceSurface));
5329 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5334 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5336 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5337 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5338 data returned by GetData non-power2 width/height with hardware non-power2
5339 pow2Width/height are set to surface width height, repacking isn't needed so it
5340 doesn't matter which function gets called. */
5341 glTexSubImage2D(glDescription->target
5342 ,glDescription->level
5347 ,glDescription->glFormat
5348 ,glDescription->glType
5349 ,IWineD3DSurface_GetData(pSourceSurface)
5353 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5354 glTexSubImage2D(glDescription->target
5355 ,glDescription->level
5358 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5359 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5360 ,glDescription->glFormat
5361 ,glDescription->glType
5362 ,IWineD3DSurface_GetData(pSourceSurface)
5368 checkGLcall("glTexSubImage2D");
5369 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5371 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5372 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5373 * surface bigger than it needs to be hmm.. */
5374 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5375 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5376 IWineD3DBaseTexture_Release(baseTexture);
5379 glDisable(textureDimensions); /* This needs to be managed better.... */
5385 /* Implementation details at http://developer.nvidia.com/attach/6494
5387 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5388 hmm.. no longer supported use
5389 OpenGL evaluators or tessellate surfaces within your application.
5392 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5393 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5395 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5396 FIXME("(%p) : Stub\n", This);
5401 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5402 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5405 FIXME("(%p) : Stub\n", This);
5409 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5411 TRACE("(%p) Handle(%d)\n", This, Handle);
5412 FIXME("(%p) : Stub\n", This);
5416 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5418 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5420 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5422 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5423 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5424 return WINED3DERR_INVALIDCALL;
5427 /* Just forward this to the DirectDraw blitting engine */
5428 memset(&BltFx, 0, sizeof(BltFx));
5429 BltFx.dwSize = sizeof(BltFx);
5430 BltFx.u5.dwFillColor = color;
5431 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5434 /* rendertarget and deptth stencil functions */
5435 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5438 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5439 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5440 return WINED3DERR_INVALIDCALL;
5443 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5444 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5445 /* Note inc ref on returned surface */
5446 if(*ppRenderTarget != NULL)
5447 IWineD3DSurface_AddRef(*ppRenderTarget);
5451 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5453 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5454 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5455 IWineD3DSwapChainImpl *Swapchain;
5458 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5460 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5461 if(hr != WINED3D_OK) {
5462 ERR("Can't get the swapchain\n");
5466 /* Make sure to release the swapchain */
5467 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5469 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5470 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5471 return WINED3DERR_INVALIDCALL;
5473 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5474 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5475 return WINED3DERR_INVALIDCALL;
5478 if(Swapchain->frontBuffer != Front) {
5479 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5481 if(Swapchain->frontBuffer)
5482 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5483 Swapchain->frontBuffer = Front;
5485 if(Swapchain->frontBuffer) {
5486 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5490 if(Back && !Swapchain->backBuffer) {
5491 /* We need memory for the back buffer array - only one back buffer this way */
5492 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5493 if(!Swapchain->backBuffer) {
5494 ERR("Out of memory\n");
5495 return E_OUTOFMEMORY;
5499 if(Swapchain->backBuffer[0] != Back) {
5500 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5502 if(!Swapchain->backBuffer[0]) {
5503 /* GL was told to draw to the front buffer at creation,
5506 glDrawBuffer(GL_BACK);
5507 checkGLcall("glDrawBuffer(GL_BACK)");
5508 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5509 Swapchain->presentParms.BackBufferCount = 1;
5511 /* That makes problems - disable for now */
5512 /* glDrawBuffer(GL_FRONT); */
5513 checkGLcall("glDrawBuffer(GL_FRONT)");
5514 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5515 Swapchain->presentParms.BackBufferCount = 0;
5519 if(Swapchain->backBuffer[0])
5520 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5521 Swapchain->backBuffer[0] = Back;
5523 if(Swapchain->backBuffer[0]) {
5524 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5526 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5534 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5536 *ppZStencilSurface = This->depthStencilBuffer;
5537 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5539 if(*ppZStencilSurface != NULL) {
5540 /* Note inc ref on returned surface */
5541 IWineD3DSurface_AddRef(*ppZStencilSurface);
5546 static void bind_fbo(IWineD3DDevice *iface) {
5547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5550 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5551 checkGLcall("glGenFramebuffersEXT()");
5553 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5554 checkGLcall("glBindFramebuffer()");
5557 /* TODO: Handle stencil attachments */
5558 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5560 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5562 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5566 if (depth_stencil_impl) {
5567 GLenum texttarget, target;
5568 GLint old_binding = 0;
5570 IWineD3DSurface_PreLoad(depth_stencil);
5571 texttarget = depth_stencil_impl->glDescription.target;
5572 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5574 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5575 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5576 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5577 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5578 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5579 glBindTexture(target, old_binding);
5581 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5582 checkGLcall("glFramebufferTexture2DEXT()");
5584 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5585 checkGLcall("glFramebufferTexture2DEXT()");
5588 if (!This->render_offscreen) {
5589 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5590 checkGLcall("glBindFramebuffer()");
5594 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5596 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5598 if (idx >= GL_LIMITS(buffers)) {
5599 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5605 GLenum texttarget, target;
5606 GLint old_binding = 0;
5608 IWineD3DSurface_PreLoad(render_target);
5609 texttarget = rtimpl->glDescription.target;
5610 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5612 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5613 glBindTexture(target, rtimpl->glDescription.textureName);
5614 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5615 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5616 glBindTexture(target, old_binding);
5618 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5619 checkGLcall("glFramebufferTexture2DEXT()");
5621 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5623 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5624 checkGLcall("glFramebufferTexture2DEXT()");
5626 This->draw_buffers[idx] = GL_NONE;
5629 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5630 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5631 checkGLcall("glDrawBuffers()");
5634 if (!This->render_offscreen) {
5635 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5636 checkGLcall("glBindFramebuffer()");
5640 /* internal static helper functions */
5641 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5642 IWineD3DSurface *RenderSurface);
5644 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 HRESULT hr = WINED3D_OK;
5647 WINED3DVIEWPORT viewport;
5649 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5651 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5652 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5653 return WINED3DERR_INVALIDCALL;
5656 /* MSDN says that null disables the render target
5657 but a device must always be associated with a render target
5658 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5660 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5663 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5664 FIXME("Trying to set render target 0 to NULL\n");
5665 return WINED3DERR_INVALIDCALL;
5667 /* TODO: replace Impl* usage with interface usage */
5668 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5669 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);
5670 return WINED3DERR_INVALIDCALL;
5672 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5673 * builds, but I think wine counts as a 'debug' build for now.
5674 ******************************/
5675 /* If we are trying to set what we already have, don't bother */
5676 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5677 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5679 /* Otherwise, set the render target up */
5681 if (!This->sceneEnded) {
5682 IWineD3DDevice_EndScene(iface);
5684 TRACE("clearing renderer\n");
5685 /* IWineD3DDeviceImpl_CleanRender(iface); */
5686 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5687 depending on the renter target implementation being used.
5688 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5689 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5690 stencil buffer and incure an extra memory overhead */
5691 if (RenderTargetIndex == 0) {
5692 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5697 /* Replace the render target */
5698 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5699 This->render_targets[RenderTargetIndex] = pRenderTarget;
5700 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5702 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5703 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5707 if (SUCCEEDED(hr)) {
5708 /* Finally, reset the viewport as the MSDN states. */
5709 /* TODO: Replace impl usage */
5710 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5711 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5714 viewport.MaxZ = 1.0f;
5715 viewport.MinZ = 0.0f;
5716 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5718 FIXME("Unknown error setting the render target\n");
5720 This->sceneEnded = FALSE;
5724 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5726 HRESULT hr = WINED3D_OK;
5727 IWineD3DSurface *tmp;
5729 TRACE("(%p) Swapping z-buffer\n",This);
5731 if (pNewZStencil == This->stencilBufferTarget) {
5732 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5734 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5735 * depending on the renter target implementation being used.
5736 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5737 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5738 * stencil buffer and incure an extra memory overhead
5739 ******************************************************/
5742 tmp = This->stencilBufferTarget;
5743 This->stencilBufferTarget = pNewZStencil;
5744 /* should we be calling the parent or the wined3d surface? */
5745 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5746 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5748 /** TODO: glEnable/glDisable on depth/stencil depending on
5749 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5750 **********************************************************/
5751 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5752 set_depth_stencil_fbo(iface, pNewZStencil);
5760 #ifdef GL_VERSION_1_3
5761 /* Internal functions not in DirectX */
5762 /** TODO: move this off to the opengl context manager
5763 *(the swapchain doesn't need to know anything about offscreen rendering!)
5764 ****************************************************/
5766 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5770 TRACE("(%p), %p\n", This, swapchain);
5772 if (swapchain->win != swapchain->drawable) {
5773 /* Set everything back the way it ws */
5774 swapchain->render_ctx = swapchain->glCtx;
5775 swapchain->drawable = swapchain->win;
5780 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5781 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5785 unsigned int height;
5786 WINED3DFORMAT format;
5787 WINED3DSURFACE_DESC surfaceDesc;
5788 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5789 surfaceDesc.Width = &width;
5790 surfaceDesc.Height = &height;
5791 surfaceDesc.Format = &format;
5792 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5794 /* I need a get width/height function (and should do something with the format) */
5795 for (i = 0; i < CONTEXT_CACHE; ++i) {
5796 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5797 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5798 the pSurface can be set to 0 allowing it to be reused from cache **/
5799 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5800 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5801 *context = &This->contextCache[i];
5804 if (This->contextCache[i].Width == 0) {
5805 This->contextCache[i].pSurface = pSurface;
5806 This->contextCache[i].Width = width;
5807 This->contextCache[i].Height = height;
5808 *context = &This->contextCache[i];
5812 if (i == CONTEXT_CACHE) {
5813 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5814 glContext *dropContext = 0;
5815 for (i = 0; i < CONTEXT_CACHE; i++) {
5816 if (This->contextCache[i].usedcount < minUsage) {
5817 dropContext = &This->contextCache[i];
5818 minUsage = This->contextCache[i].usedcount;
5821 /* clean up the context (this doesn't work for ATI at the moment */
5823 glXDestroyContext(swapchain->display, dropContext->context);
5824 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5827 dropContext->Width = 0;
5828 dropContext->pSurface = pSurface;
5829 *context = dropContext;
5831 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5832 for (i = 0; i < CONTEXT_CACHE; i++) {
5833 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
5837 if (*context != NULL)
5840 return E_OUTOFMEMORY;
5844 /* Reapply the device stateblock */
5845 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
5848 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5851 /* Disable recording */
5852 oldUpdateStateBlock = This->updateStateBlock;
5853 oldRecording= This->isRecordingState;
5854 This->isRecordingState = FALSE;
5855 This->updateStateBlock = This->stateBlock;
5857 /* Reapply the state block */
5858 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
5860 /* Temporaryily mark all render states dirty to force reapplication
5861 * until the context management for is integrated with the state management
5862 * The same for the pixel shader, sampler states and texture stage states are marked
5863 * dirty my StateBlock::Apply already
5865 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
5866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
5868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5870 /* Restore recording */
5871 This->isRecordingState = oldRecording;
5872 This->updateStateBlock = oldUpdateStateBlock;
5875 /* Set offscreen rendering. When rendering offscreen the surface will be
5876 * rendered upside down to compensate for the fact that D3D texture coordinates
5877 * are flipped compared to GL texture coordinates. The cullmode is affected by
5878 * this, so it must be updated. To update the cullmode stateblock recording has
5879 * to be temporarily disabled. The new state management code will hopefully
5880 * make this unnecessary */
5881 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
5884 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5886 /* Nothing to update, return. */
5887 if (This->render_offscreen == isTexture) return;
5889 /* Disable recording */
5890 oldUpdateStateBlock = This->updateStateBlock;
5891 oldRecording= This->isRecordingState;
5892 This->isRecordingState = FALSE;
5893 This->updateStateBlock = This->stateBlock;
5895 This->render_offscreen = isTexture;
5896 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
5897 This->depth_copy_state = WINED3D_DCS_COPY;
5899 This->last_was_rhw = FALSE;
5900 This->proj_valid = FALSE;
5901 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
5903 /* Restore recording */
5904 This->isRecordingState = oldRecording;
5905 This->updateStateBlock = oldUpdateStateBlock;
5908 /* Returns an array of compatible FBconfig(s).
5909 * The array must be freed with XFree. Requires ENTER_GL() */
5911 static GLXFBConfig* device_find_fbconfigs(
5912 IWineD3DDeviceImpl* This,
5913 IWineD3DSwapChainImpl* implicitSwapchainImpl,
5914 IWineD3DSurface* RenderSurface) {
5916 GLXFBConfig* cfgs = NULL;
5921 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
5922 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
5923 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
5926 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5927 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5930 #define PUSH1(att) attribs[nAttribs++] = (att);
5931 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5933 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
5935 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
5936 PUSH2(GLX_X_RENDERABLE, TRUE);
5937 PUSH2(GLX_DOUBLEBUFFER, TRUE);
5938 TRACE("calling makeglcfg\n");
5939 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
5941 TRACE("calling chooseFGConfig\n");
5942 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5943 DefaultScreen(implicitSwapchainImpl->display),
5946 /* OK we didn't find the exact config, so use any reasonable match */
5947 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
5949 static BOOL show_message = TRUE;
5951 ERR("Failed to find exact match, finding alternative but you may "
5952 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
5953 show_message = FALSE;
5956 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
5957 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
5958 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
5959 PUSH2(GLX_DOUBLEBUFFER, FALSE);
5960 TRACE("calling makeglcfg\n");
5961 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
5963 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5964 DefaultScreen(implicitSwapchainImpl->display),
5969 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
5970 BackBufferFormat, debug_d3dformat(BackBufferFormat),
5971 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
5975 for (i = 0; i < nCfgs; ++i) {
5976 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
5977 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
5978 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
5980 if (NULL != This->renderTarget) {
5982 vcheckGLcall("glFlush");
5983 /** This is only useful if the old render target was a swapchain,
5984 * we need to supercede this with a function that displays
5985 * the current buffer on the screen. This is easy to do in glx1.3 but
5986 * we need to do copy-write pixels in glx 1.2.
5987 ************************************************/
5988 glXSwapBuffers(implicitSwapChainImpl->display,
5989 implicitSwapChainImpl->drawable);
5990 printf("Hit Enter to get next frame ...\n");
6001 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6002 * the functionality needs splitting up so that we don't do more than we should do.
6003 * this only seems to impact performance a little.
6004 ******************************/
6005 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6006 IWineD3DSurface *RenderSurface) {
6009 * Currently only active for GLX >= 1.3
6010 * for others versions we'll have to use GLXPixmaps
6012 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6013 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6014 * so only check OpenGL version
6015 * ..........................
6016 * I don't believe that it is a problem with NVidia headers,
6017 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6018 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6020 * Your application will report GLX version 1.2 on glXQueryVersion.
6021 * However, it is safe to call the GLX 1.3 functions as described below.
6023 #if defined(GL_VERSION_1_3)
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6026 GLXFBConfig* cfgs = NULL;
6027 IWineD3DSwapChain *currentSwapchain;
6028 IWineD3DSwapChainImpl *currentSwapchainImpl;
6029 IWineD3DSwapChain *implicitSwapchain;
6030 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6031 IWineD3DSwapChain *renderSurfaceSwapchain;
6032 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6034 /* Obtain a reference to the device implicit swapchain,
6035 * the swapchain of the current render target,
6036 * and the swapchain of the new render target.
6037 * Fallback to device implicit swapchain if the current render target doesn't have one */
6038 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6039 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6040 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)¤tSwapchain);
6041 if (currentSwapchain == NULL)
6042 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
6044 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6045 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6046 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6051 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6052 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6053 **********************************************************************/
6054 if (renderSurfaceSwapchain != NULL) {
6056 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6057 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6058 TRACE("making swapchain active\n");
6059 if (RenderSurface != This->render_targets[0]) {
6060 BOOL backbuf = FALSE;
6063 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6064 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6072 /* This could be flagged so that some operations work directly with the front buffer */
6073 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6075 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6076 renderSurfaceSwapchainImpl->win,
6077 renderSurfaceSwapchainImpl->glCtx) == False) {
6079 TRACE("Error in setting current context: context %p drawable %ld !\n",
6080 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6082 checkGLcall("glXMakeContextCurrent");
6084 /* Clean up the old context */
6085 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6087 /* Reapply the stateblock, and set the device not to render to texture */
6088 device_reapply_stateblock(This);
6089 device_render_to_texture(This, FALSE);
6092 /* Offscreen rendering: PBuffers (currently disabled).
6093 * Also note that this path is never reached if FBOs are supported */
6094 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6095 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6097 /** ********************************************************************
6098 * This is a quickly hacked out implementation of offscreen textures.
6099 * It will work in most cases but there may be problems if the client
6100 * modifies the texture directly, or expects the contents of the rendertarget
6103 * There are some real speed vs compatibility issues here:
6104 * we should really use a new context for every texture, but that eats ram.
6105 * we should also be restoring the texture to the pbuffer but that eats CPU
6106 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6107 * but if this means reusing the display backbuffer then we need to make sure that
6108 * states are correctly preserved.
6109 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6110 * and gain a good performance increase at the cost of compatibility.
6111 * I would suggest that, when this is the case, a user configurable flag be made
6112 * available, allowing the user to choose the best emulated experience for them.
6113 *********************************************************************/
6115 XVisualInfo *visinfo;
6116 glContext *newContext;
6118 /* Here were using a shared context model */
6119 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6120 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6123 /* If the context doesn't exist then create a new one */
6124 /* TODO: This should really be part of findGlContext */
6125 if (NULL == newContext->context) {
6130 TRACE("making new buffer\n");
6131 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6132 attribs[nAttribs++] = newContext->Width;
6133 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6134 attribs[nAttribs++] = newContext->Height;
6135 attribs[nAttribs++] = None;
6137 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6139 /** ****************************************
6140 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6142 * In future releases, we may provide the calls glXCreateNewContext,
6143 * glXQueryDrawable and glXMakeContextCurrent.
6144 * so until then we have to use glXGetVisualFromFBConfig &co..
6145 ********************************************/
6147 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6149 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6151 newContext->context = glXCreateContext(
6152 implicitSwapchainImpl->display, visinfo,
6153 implicitSwapchainImpl->glCtx, GL_TRUE);
6158 if (NULL == newContext || NULL == newContext->context) {
6159 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6161 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6162 if (glXMakeCurrent(implicitSwapchainImpl->display,
6163 newContext->drawable, newContext->context) == False) {
6165 TRACE("Error in setting current context: context %p drawable %ld\n",
6166 newContext->context, newContext->drawable);
6168 checkGLcall("glXMakeContextCurrent");
6170 /* Clean up the old context */
6171 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6173 /* Reapply stateblock, and set device to render to a texture */
6174 device_reapply_stateblock(This);
6175 device_render_to_texture(This, TRUE);
6177 /* Set the current context of the swapchain to the new context */
6178 implicitSwapchainImpl->drawable = newContext->drawable;
6179 implicitSwapchainImpl->render_ctx = newContext->context;
6182 /* Same context, but update render_offscreen and cull mode */
6183 device_render_to_texture(This, TRUE);
6186 if (cfgs != NULL) XFree(cfgs);
6187 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6188 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6189 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6195 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6196 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6198 /* TODO: the use of Impl is deprecated. */
6199 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6201 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6203 /* some basic validation checks */
6204 if(This->cursorTexture) {
6206 glDeleteTextures(1, &This->cursorTexture);
6208 This->cursorTexture = 0;
6212 /* MSDN: Cursor must be A8R8G8B8 */
6213 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6214 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6215 return WINED3DERR_INVALIDCALL;
6218 /* MSDN: Cursor must be smaller than the display mode */
6219 if(pSur->currentDesc.Width > This->ddraw_width ||
6220 pSur->currentDesc.Height > This->ddraw_height) {
6221 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);
6222 return WINED3DERR_INVALIDCALL;
6225 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6226 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6227 * Texture and Blitting code to draw the cursor
6229 pSur->Flags |= SFLAG_FORCELOAD;
6230 IWineD3DSurface_PreLoad(pCursorBitmap);
6231 pSur->Flags &= ~SFLAG_FORCELOAD;
6232 /* Do not store the surface's pointer because the application may release
6233 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6234 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6236 This->cursorTexture = pSur->glDescription.textureName;
6237 This->cursorWidth = pSur->currentDesc.Width;
6238 This->cursorHeight = pSur->currentDesc.Height;
6239 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6242 This->xHotSpot = XHotSpot;
6243 This->yHotSpot = YHotSpot;
6247 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6249 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6251 This->xScreenSpace = XScreenSpace;
6252 This->yScreenSpace = YScreenSpace;
6258 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6260 BOOL oldVisible = This->bCursorVisible;
6261 TRACE("(%p) : visible(%d)\n", This, bShow);
6263 if(This->cursorTexture)
6264 This->bCursorVisible = bShow;
6269 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6271 TRACE("(%p) : state (%u)\n", This, This->state);
6272 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6273 switch (This->state) {
6276 case WINED3DERR_DEVICELOST:
6278 ResourceList *resourceList = This->resources;
6279 while (NULL != resourceList) {
6280 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6281 return WINED3DERR_DEVICENOTRESET;
6282 resourceList = resourceList->next;
6284 return WINED3DERR_DEVICELOST;
6286 case WINED3DERR_DRIVERINTERNALERROR:
6287 return WINED3DERR_DRIVERINTERNALERROR;
6291 return WINED3DERR_DRIVERINTERNALERROR;
6295 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6297 /** FIXME: Resource tracking needs to be done,
6298 * The closes we can do to this is set the priorities of all managed textures low
6299 * and then reset them.
6300 ***********************************************************/
6301 FIXME("(%p) : stub\n", This);
6305 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6306 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6307 if(surface->Flags & SFLAG_DIBSECTION) {
6308 /* Release the DC */
6309 SelectObject(surface->hDC, surface->dib.holdbitmap);
6310 DeleteDC(surface->hDC);
6311 /* Release the DIB section */
6312 DeleteObject(surface->dib.DIBsection);
6313 surface->dib.bitmap_data = NULL;
6314 surface->resource.allocatedMemory = NULL;
6315 surface->Flags &= ~SFLAG_DIBSECTION;
6317 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6318 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6319 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6320 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6321 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6323 surface->pow2Width = surface->pow2Height = 1;
6324 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6325 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6327 if(surface->glDescription.textureName) {
6329 glDeleteTextures(1, &surface->glDescription.textureName);
6331 surface->glDescription.textureName = 0;
6333 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6334 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6335 surface->Flags |= SFLAG_NONPOW2;
6337 surface->Flags &= ~SFLAG_NONPOW2;
6339 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6340 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6343 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6345 IWineD3DSwapChainImpl *swapchain;
6347 BOOL DisplayModeChanged = FALSE;
6348 WINED3DDISPLAYMODE mode;
6349 TRACE("(%p)\n", This);
6351 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6353 ERR("Failed to get the first implicit swapchain\n");
6357 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6358 * on an existing gl context, so there's no real need for recreation.
6360 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6362 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6364 TRACE("New params:\n");
6365 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6366 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6367 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6368 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6369 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6370 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6371 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6372 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6373 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6374 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6375 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6376 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6377 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6379 /* No special treatment of these parameters. Just store them */
6380 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6381 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6382 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6383 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6385 /* What to do about these? */
6386 if(*pPresentationParameters->BackBufferCount != 0 &&
6387 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6388 ERR("Cannot change the back buffer count yet\n");
6390 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6391 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6392 ERR("Cannot change the back buffer format yet\n");
6394 if(*pPresentationParameters->hDeviceWindow != NULL &&
6395 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6396 ERR("Cannot change the device window yet\n");
6398 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6399 ERR("What do do about a changed auto depth stencil parameter?\n");
6402 if(*pPresentationParameters->Windowed) {
6403 mode.Width = swapchain->orig_width;
6404 mode.Height = swapchain->orig_height;
6405 mode.RefreshRate = 0;
6406 mode.Format = swapchain->presentParms.BackBufferFormat;
6408 mode.Width = *pPresentationParameters->BackBufferWidth;
6409 mode.Height = *pPresentationParameters->BackBufferHeight;
6410 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6411 mode.Format = swapchain->presentParms.BackBufferFormat;
6414 /* Should Width == 800 && Height == 0 set 800x600? */
6415 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6416 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6417 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6424 vp.Width = *pPresentationParameters->BackBufferWidth;
6425 vp.Height = *pPresentationParameters->BackBufferHeight;
6429 if(!*pPresentationParameters->Windowed) {
6430 DisplayModeChanged = TRUE;
6432 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6433 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6435 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6436 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6437 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6440 /* Now set the new viewport */
6441 IWineD3DDevice_SetViewport(iface, &vp);
6444 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6445 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6446 DisplayModeChanged) {
6447 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6450 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6454 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6456 /** FIXME: always true at the moment **/
6457 if(!bEnableDialogs) {
6458 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6464 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6466 TRACE("(%p) : pParameters %p\n", This, pParameters);
6468 *pParameters = This->createParms;
6472 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6473 IWineD3DSwapChain *swapchain;
6474 HRESULT hrc = WINED3D_OK;
6476 TRACE("Relaying to swapchain\n");
6478 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6479 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6480 IWineD3DSwapChain_Release(swapchain);
6485 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6486 IWineD3DSwapChain *swapchain;
6487 HRESULT hrc = WINED3D_OK;
6489 TRACE("Relaying to swapchain\n");
6491 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6492 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6493 IWineD3DSwapChain_Release(swapchain);
6499 /** ********************************************************
6500 * Notification functions
6501 ** ********************************************************/
6502 /** This function must be called in the release of a resource when ref == 0,
6503 * the contents of resource must still be correct,
6504 * any handels to other resource held by the caller must be closed
6505 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6506 *****************************************************/
6507 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6509 ResourceList* resourceList;
6511 TRACE("(%p) : resource %p\n", This, resource);
6513 EnterCriticalSection(&resourceStoreCriticalSection);
6515 /* add a new texture to the frot of the linked list */
6516 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6517 resourceList->resource = resource;
6519 /* Get the old head */
6520 resourceList->next = This->resources;
6522 This->resources = resourceList;
6523 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6526 LeaveCriticalSection(&resourceStoreCriticalSection);
6531 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 ResourceList* resourceList = NULL;
6534 ResourceList* previousResourceList = NULL;
6536 TRACE("(%p) : resource %p\n", This, resource);
6539 EnterCriticalSection(&resourceStoreCriticalSection);
6541 resourceList = This->resources;
6543 while (resourceList != NULL) {
6544 if(resourceList->resource == resource) break;
6545 previousResourceList = resourceList;
6546 resourceList = resourceList->next;
6549 if (resourceList == NULL) {
6550 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6552 LeaveCriticalSection(&resourceStoreCriticalSection);
6556 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6558 /* make sure we don't leave a hole in the list */
6559 if (previousResourceList != NULL) {
6560 previousResourceList->next = resourceList->next;
6562 This->resources = resourceList->next;
6566 LeaveCriticalSection(&resourceStoreCriticalSection);
6572 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6576 TRACE("(%p) : resource %p\n", This, resource);
6577 switch(IWineD3DResource_GetType(resource)){
6578 case WINED3DRTYPE_SURFACE:
6579 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6581 case WINED3DRTYPE_TEXTURE:
6582 case WINED3DRTYPE_CUBETEXTURE:
6583 case WINED3DRTYPE_VOLUMETEXTURE:
6584 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6585 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6586 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6587 This->stateBlock->textures[counter] = NULL;
6589 if (This->updateStateBlock != This->stateBlock ){
6590 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6591 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6592 This->updateStateBlock->textures[counter] = NULL;
6597 case WINED3DRTYPE_VOLUME:
6598 /* TODO: nothing really? */
6600 case WINED3DRTYPE_VERTEXBUFFER:
6601 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6604 TRACE("Cleaning up stream pointers\n");
6606 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6607 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6608 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6610 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6611 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6612 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6613 This->updateStateBlock->streamSource[streamNumber] = 0;
6614 /* Set changed flag? */
6617 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) */
6618 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6619 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6620 This->stateBlock->streamSource[streamNumber] = 0;
6623 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6624 else { /* This shouldn't happen */
6625 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6632 case WINED3DRTYPE_INDEXBUFFER:
6633 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6634 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6635 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6636 This->updateStateBlock->pIndexData = NULL;
6639 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6640 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6641 This->stateBlock->pIndexData = NULL;
6647 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6652 /* Remove the resoruce from the resourceStore */
6653 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6655 TRACE("Resource released\n");
6659 /**********************************************************
6660 * IWineD3DDevice VTbl follows
6661 **********************************************************/
6663 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6665 /*** IUnknown methods ***/
6666 IWineD3DDeviceImpl_QueryInterface,
6667 IWineD3DDeviceImpl_AddRef,
6668 IWineD3DDeviceImpl_Release,
6669 /*** IWineD3DDevice methods ***/
6670 IWineD3DDeviceImpl_GetParent,
6671 /*** Creation methods**/
6672 IWineD3DDeviceImpl_CreateVertexBuffer,
6673 IWineD3DDeviceImpl_CreateIndexBuffer,
6674 IWineD3DDeviceImpl_CreateStateBlock,
6675 IWineD3DDeviceImpl_CreateSurface,
6676 IWineD3DDeviceImpl_CreateTexture,
6677 IWineD3DDeviceImpl_CreateVolumeTexture,
6678 IWineD3DDeviceImpl_CreateVolume,
6679 IWineD3DDeviceImpl_CreateCubeTexture,
6680 IWineD3DDeviceImpl_CreateQuery,
6681 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6682 IWineD3DDeviceImpl_CreateVertexDeclaration,
6683 IWineD3DDeviceImpl_CreateVertexShader,
6684 IWineD3DDeviceImpl_CreatePixelShader,
6685 IWineD3DDeviceImpl_CreatePalette,
6686 /*** Odd functions **/
6687 IWineD3DDeviceImpl_Init3D,
6688 IWineD3DDeviceImpl_Uninit3D,
6689 IWineD3DDeviceImpl_SetFullscreen,
6690 IWineD3DDeviceImpl_EnumDisplayModes,
6691 IWineD3DDeviceImpl_EvictManagedResources,
6692 IWineD3DDeviceImpl_GetAvailableTextureMem,
6693 IWineD3DDeviceImpl_GetBackBuffer,
6694 IWineD3DDeviceImpl_GetCreationParameters,
6695 IWineD3DDeviceImpl_GetDeviceCaps,
6696 IWineD3DDeviceImpl_GetDirect3D,
6697 IWineD3DDeviceImpl_GetDisplayMode,
6698 IWineD3DDeviceImpl_SetDisplayMode,
6699 IWineD3DDeviceImpl_GetHWND,
6700 IWineD3DDeviceImpl_SetHWND,
6701 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6702 IWineD3DDeviceImpl_GetRasterStatus,
6703 IWineD3DDeviceImpl_GetSwapChain,
6704 IWineD3DDeviceImpl_Reset,
6705 IWineD3DDeviceImpl_SetDialogBoxMode,
6706 IWineD3DDeviceImpl_SetCursorProperties,
6707 IWineD3DDeviceImpl_SetCursorPosition,
6708 IWineD3DDeviceImpl_ShowCursor,
6709 IWineD3DDeviceImpl_TestCooperativeLevel,
6710 /*** Getters and setters **/
6711 IWineD3DDeviceImpl_SetClipPlane,
6712 IWineD3DDeviceImpl_GetClipPlane,
6713 IWineD3DDeviceImpl_SetClipStatus,
6714 IWineD3DDeviceImpl_GetClipStatus,
6715 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6716 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6717 IWineD3DDeviceImpl_SetDepthStencilSurface,
6718 IWineD3DDeviceImpl_GetDepthStencilSurface,
6719 IWineD3DDeviceImpl_SetFVF,
6720 IWineD3DDeviceImpl_GetFVF,
6721 IWineD3DDeviceImpl_SetGammaRamp,
6722 IWineD3DDeviceImpl_GetGammaRamp,
6723 IWineD3DDeviceImpl_SetIndices,
6724 IWineD3DDeviceImpl_GetIndices,
6725 IWineD3DDeviceImpl_SetBasevertexIndex,
6726 IWineD3DDeviceImpl_SetLight,
6727 IWineD3DDeviceImpl_GetLight,
6728 IWineD3DDeviceImpl_SetLightEnable,
6729 IWineD3DDeviceImpl_GetLightEnable,
6730 IWineD3DDeviceImpl_SetMaterial,
6731 IWineD3DDeviceImpl_GetMaterial,
6732 IWineD3DDeviceImpl_SetNPatchMode,
6733 IWineD3DDeviceImpl_GetNPatchMode,
6734 IWineD3DDeviceImpl_SetPaletteEntries,
6735 IWineD3DDeviceImpl_GetPaletteEntries,
6736 IWineD3DDeviceImpl_SetPixelShader,
6737 IWineD3DDeviceImpl_GetPixelShader,
6738 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6739 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6740 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6741 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6742 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6743 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6744 IWineD3DDeviceImpl_SetRenderState,
6745 IWineD3DDeviceImpl_GetRenderState,
6746 IWineD3DDeviceImpl_SetRenderTarget,
6747 IWineD3DDeviceImpl_GetRenderTarget,
6748 IWineD3DDeviceImpl_SetFrontBackBuffers,
6749 IWineD3DDeviceImpl_SetSamplerState,
6750 IWineD3DDeviceImpl_GetSamplerState,
6751 IWineD3DDeviceImpl_SetScissorRect,
6752 IWineD3DDeviceImpl_GetScissorRect,
6753 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6754 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6755 IWineD3DDeviceImpl_SetStreamSource,
6756 IWineD3DDeviceImpl_GetStreamSource,
6757 IWineD3DDeviceImpl_SetStreamSourceFreq,
6758 IWineD3DDeviceImpl_GetStreamSourceFreq,
6759 IWineD3DDeviceImpl_SetTexture,
6760 IWineD3DDeviceImpl_GetTexture,
6761 IWineD3DDeviceImpl_SetTextureStageState,
6762 IWineD3DDeviceImpl_GetTextureStageState,
6763 IWineD3DDeviceImpl_SetTransform,
6764 IWineD3DDeviceImpl_GetTransform,
6765 IWineD3DDeviceImpl_SetVertexDeclaration,
6766 IWineD3DDeviceImpl_GetVertexDeclaration,
6767 IWineD3DDeviceImpl_SetVertexShader,
6768 IWineD3DDeviceImpl_GetVertexShader,
6769 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6770 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6771 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6772 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6773 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6774 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6775 IWineD3DDeviceImpl_SetViewport,
6776 IWineD3DDeviceImpl_GetViewport,
6777 IWineD3DDeviceImpl_MultiplyTransform,
6778 IWineD3DDeviceImpl_ValidateDevice,
6779 IWineD3DDeviceImpl_ProcessVertices,
6780 /*** State block ***/
6781 IWineD3DDeviceImpl_BeginStateBlock,
6782 IWineD3DDeviceImpl_EndStateBlock,
6783 /*** Scene management ***/
6784 IWineD3DDeviceImpl_BeginScene,
6785 IWineD3DDeviceImpl_EndScene,
6786 IWineD3DDeviceImpl_Present,
6787 IWineD3DDeviceImpl_Clear,
6789 IWineD3DDeviceImpl_DrawPrimitive,
6790 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6791 IWineD3DDeviceImpl_DrawPrimitiveUP,
6792 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6793 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6794 IWineD3DDeviceImpl_DrawRectPatch,
6795 IWineD3DDeviceImpl_DrawTriPatch,
6796 IWineD3DDeviceImpl_DeletePatch,
6797 IWineD3DDeviceImpl_ColorFill,
6798 IWineD3DDeviceImpl_UpdateTexture,
6799 IWineD3DDeviceImpl_UpdateSurface,
6800 IWineD3DDeviceImpl_StretchRect,
6801 IWineD3DDeviceImpl_GetRenderTargetData,
6802 IWineD3DDeviceImpl_GetFrontBufferData,
6803 /*** object tracking ***/
6804 IWineD3DDeviceImpl_ResourceReleased
6808 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6809 WINED3DRS_ALPHABLENDENABLE ,
6810 WINED3DRS_ALPHAFUNC ,
6811 WINED3DRS_ALPHAREF ,
6812 WINED3DRS_ALPHATESTENABLE ,
6814 WINED3DRS_COLORWRITEENABLE ,
6815 WINED3DRS_DESTBLEND ,
6816 WINED3DRS_DITHERENABLE ,
6817 WINED3DRS_FILLMODE ,
6818 WINED3DRS_FOGDENSITY ,
6820 WINED3DRS_FOGSTART ,
6821 WINED3DRS_LASTPIXEL ,
6822 WINED3DRS_SHADEMODE ,
6823 WINED3DRS_SRCBLEND ,
6824 WINED3DRS_STENCILENABLE ,
6825 WINED3DRS_STENCILFAIL ,
6826 WINED3DRS_STENCILFUNC ,
6827 WINED3DRS_STENCILMASK ,
6828 WINED3DRS_STENCILPASS ,
6829 WINED3DRS_STENCILREF ,
6830 WINED3DRS_STENCILWRITEMASK ,
6831 WINED3DRS_STENCILZFAIL ,
6832 WINED3DRS_TEXTUREFACTOR ,
6843 WINED3DRS_ZWRITEENABLE
6846 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6847 WINED3DTSS_ADDRESSW ,
6848 WINED3DTSS_ALPHAARG0 ,
6849 WINED3DTSS_ALPHAARG1 ,
6850 WINED3DTSS_ALPHAARG2 ,
6851 WINED3DTSS_ALPHAOP ,
6852 WINED3DTSS_BUMPENVLOFFSET ,
6853 WINED3DTSS_BUMPENVLSCALE ,
6854 WINED3DTSS_BUMPENVMAT00 ,
6855 WINED3DTSS_BUMPENVMAT01 ,
6856 WINED3DTSS_BUMPENVMAT10 ,
6857 WINED3DTSS_BUMPENVMAT11 ,
6858 WINED3DTSS_COLORARG0 ,
6859 WINED3DTSS_COLORARG1 ,
6860 WINED3DTSS_COLORARG2 ,
6861 WINED3DTSS_COLOROP ,
6862 WINED3DTSS_RESULTARG ,
6863 WINED3DTSS_TEXCOORDINDEX ,
6864 WINED3DTSS_TEXTURETRANSFORMFLAGS
6867 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6868 WINED3DSAMP_ADDRESSU ,
6869 WINED3DSAMP_ADDRESSV ,
6870 WINED3DSAMP_ADDRESSW ,
6871 WINED3DSAMP_BORDERCOLOR ,
6872 WINED3DSAMP_MAGFILTER ,
6873 WINED3DSAMP_MINFILTER ,
6874 WINED3DSAMP_MIPFILTER ,
6875 WINED3DSAMP_MIPMAPLODBIAS ,
6876 WINED3DSAMP_MAXMIPLEVEL ,
6877 WINED3DSAMP_MAXANISOTROPY ,
6878 WINED3DSAMP_SRGBTEXTURE ,
6879 WINED3DSAMP_ELEMENTINDEX
6882 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6884 WINED3DRS_AMBIENTMATERIALSOURCE ,
6885 WINED3DRS_CLIPPING ,
6886 WINED3DRS_CLIPPLANEENABLE ,
6887 WINED3DRS_COLORVERTEX ,
6888 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6889 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6890 WINED3DRS_FOGDENSITY ,
6892 WINED3DRS_FOGSTART ,
6893 WINED3DRS_FOGTABLEMODE ,
6894 WINED3DRS_FOGVERTEXMODE ,
6895 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6896 WINED3DRS_LIGHTING ,
6897 WINED3DRS_LOCALVIEWER ,
6898 WINED3DRS_MULTISAMPLEANTIALIAS ,
6899 WINED3DRS_MULTISAMPLEMASK ,
6900 WINED3DRS_NORMALIZENORMALS ,
6901 WINED3DRS_PATCHEDGESTYLE ,
6902 WINED3DRS_POINTSCALE_A ,
6903 WINED3DRS_POINTSCALE_B ,
6904 WINED3DRS_POINTSCALE_C ,
6905 WINED3DRS_POINTSCALEENABLE ,
6906 WINED3DRS_POINTSIZE ,
6907 WINED3DRS_POINTSIZE_MAX ,
6908 WINED3DRS_POINTSIZE_MIN ,
6909 WINED3DRS_POINTSPRITEENABLE ,
6910 WINED3DRS_RANGEFOGENABLE ,
6911 WINED3DRS_SPECULARMATERIALSOURCE ,
6912 WINED3DRS_TWEENFACTOR ,
6913 WINED3DRS_VERTEXBLEND
6916 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6917 WINED3DTSS_TEXCOORDINDEX ,
6918 WINED3DTSS_TEXTURETRANSFORMFLAGS
6921 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6922 WINED3DSAMP_DMAPOFFSET
6925 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6926 DWORD rep = StateTable[state].representative;
6930 if(!rep || isStateDirty(This, rep)) return;
6932 This->dirtyArray[This->numDirtyEntries++] = rep;
6935 This->isStateDirty[idx] |= (1 << shift);