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->view_ident = 1;
1940 This->last_was_rhw = 0;
1941 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1942 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1944 /* Clear the screen */
1945 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1947 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
1948 * This might create a problem in 2 situations:
1949 * ->The D3D default value is 0, but the opengl default value is something else
1950 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
1952 for(state = 0; state <= STATE_HIGHEST; state++) {
1953 IWineD3DDeviceImpl_MarkStateDirty(This, state);
1956 This->d3d_initialized = TRUE;
1960 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1964 TRACE("(%p)\n", This);
1966 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1968 /* Delete the mouse cursor texture */
1969 if(This->cursorTexture) {
1971 glDeleteTextures(1, &This->cursorTexture);
1973 This->cursorTexture = 0;
1976 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1977 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1980 /* Release the buffers (with sanity checks)*/
1981 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1982 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1983 if(This->depthStencilBuffer != This->stencilBufferTarget)
1984 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1986 This->stencilBufferTarget = NULL;
1988 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1989 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1990 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1992 TRACE("Setting rendertarget to NULL\n");
1993 This->render_targets[0] = NULL;
1995 if (This->depthStencilBuffer) {
1996 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1997 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1999 This->depthStencilBuffer = NULL;
2002 for(i=0; i < This->NumberOfSwapChains; i++) {
2003 TRACE("Releasing the implicit swapchain %d\n", i);
2004 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2005 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2009 HeapFree(GetProcessHeap(), 0, This->swapchains);
2010 This->swapchains = NULL;
2011 This->NumberOfSwapChains = 0;
2013 This->d3d_initialized = FALSE;
2017 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2019 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2021 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2022 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2023 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2026 This->ddraw_fullscreen = fullscreen;
2029 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2034 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2036 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2038 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2039 /* Ignore some modes if a description was passed */
2040 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2041 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2042 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2044 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2046 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2053 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2057 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2060 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2062 /* Resize the screen even without a window:
2063 * The app could have unset it with SetCooperativeLevel, but not called
2064 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2065 * but we don't have any hwnd
2068 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2069 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2070 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2071 devmode.dmPelsWidth = pMode->Width;
2072 devmode.dmPelsHeight = pMode->Height;
2074 devmode.dmDisplayFrequency = pMode->RefreshRate;
2075 if (pMode->RefreshRate != 0) {
2076 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2079 /* Only change the mode if necessary */
2080 if( (This->ddraw_width == pMode->Width) &&
2081 (This->ddraw_height == pMode->Height) &&
2082 (This->ddraw_format == pMode->Format) &&
2083 (pMode->RefreshRate == 0) ) {
2087 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2088 if (ret != DISP_CHANGE_SUCCESSFUL) {
2089 if(devmode.dmDisplayFrequency != 0) {
2090 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2091 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2092 devmode.dmDisplayFrequency = 0;
2093 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2095 if(ret != DISP_CHANGE_SUCCESSFUL) {
2096 return DDERR_INVALIDMODE;
2100 /* Store the new values */
2101 This->ddraw_width = pMode->Width;
2102 This->ddraw_height = pMode->Height;
2103 This->ddraw_format = pMode->Format;
2105 /* Only do this with a window of course */
2106 if(This->ddraw_window)
2107 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2109 /* And finally clip mouse to our screen */
2110 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2111 ClipCursor(&clip_rc);
2116 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2118 *ppD3D= This->wineD3D;
2119 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2120 IWineD3D_AddRef(*ppD3D);
2124 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2125 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2126 * into the video ram as possible and seeing how many fit
2127 * you can also get the correct initial value from nvidia and ATI's driver via X
2128 * texture memory is video memory + AGP memory
2129 *******************/
2130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2131 static BOOL showfixmes = TRUE;
2133 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2134 (wined3d_settings.emulated_textureram/(1024*1024)),
2135 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2138 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2139 (wined3d_settings.emulated_textureram/(1024*1024)),
2140 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2141 /* return simulated texture memory left */
2142 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2150 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2153 /* Update the current state block */
2154 This->updateStateBlock->changed.fvf = TRUE;
2155 This->updateStateBlock->set.fvf = TRUE;
2157 if(This->updateStateBlock->fvf == fvf) {
2158 TRACE("Application is setting the old fvf over, nothing to do\n");
2162 This->updateStateBlock->fvf = fvf;
2163 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2169 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2171 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2172 *pfvf = This->stateBlock->fvf;
2177 * Get / Set Stream Source
2179 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2181 IWineD3DVertexBuffer *oldSrc;
2183 /**TODO: instance and index data, see
2184 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2186 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2189 /* D3d9 only, but shouldn't hurt d3d8 */
2192 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2194 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2195 FIXME("stream index data not supported\n");
2197 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2198 FIXME("stream instance data not supported\n");
2202 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2204 if (StreamNumber >= MAX_STREAMS) {
2205 WARN("Stream out of range %d\n", StreamNumber);
2206 return WINED3DERR_INVALIDCALL;
2209 oldSrc = This->stateBlock->streamSource[StreamNumber];
2210 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2212 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2213 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2215 if(oldSrc == pStreamData &&
2216 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2217 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes &&
2218 This->updateStateBlock->streamFlags[StreamNumber] == streamFlags) {
2219 TRACE("Application is setting the old values over, nothing to do\n");
2223 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2225 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2226 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2228 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2230 /* Handle recording of state blocks */
2231 if (This->isRecordingState) {
2232 TRACE("Recording... not performing anything\n");
2236 /* Same stream object: no action */
2237 if (oldSrc == pStreamData)
2240 /* Need to do a getParent and pass the reffs up */
2241 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2242 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2243 so for now, just count internally */
2244 if (pStreamData != NULL) {
2245 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2246 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2247 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2249 vbImpl->stream = StreamNumber;
2250 vbImpl->Flags |= VBFLAG_STREAM;
2252 if (oldSrc != NULL) {
2253 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2261 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2265 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2266 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2269 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2271 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2272 FIXME("stream index data not supported\n");
2274 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2275 FIXME("stream instance data not supported\n");
2279 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2281 if (StreamNumber >= MAX_STREAMS) {
2282 WARN("Stream out of range %d\n", StreamNumber);
2283 return WINED3DERR_INVALIDCALL;
2285 *pStream = This->stateBlock->streamSource[StreamNumber];
2286 *pStride = This->stateBlock->streamStride[StreamNumber];
2288 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2291 if (*pStream != NULL) {
2292 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2297 /*Should be quite easy, just an extension of vertexdata
2299 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2301 The divider is a bit odd though
2303 VertexOffset = StartVertex / Divider * StreamStride +
2304 VertexIndex / Divider * StreamStride + StreamOffset
2307 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2310 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2311 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2313 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2314 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2315 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2317 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2318 FIXME("Stream indexing not fully supported\n");
2324 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2327 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2328 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2330 TRACE("(%p) : returning %d\n", This, *Divider);
2336 * Get / Set & Multiply Transform
2338 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2341 /* Most of this routine, comments included copied from ddraw tree initially: */
2342 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2344 /* Handle recording of state blocks */
2345 if (This->isRecordingState) {
2346 TRACE("Recording... not performing anything\n");
2347 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2348 This->updateStateBlock->set.transform[d3dts] = TRUE;
2349 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2354 * If the new matrix is the same as the current one,
2355 * we cut off any further processing. this seems to be a reasonable
2356 * optimization because as was noticed, some apps (warcraft3 for example)
2357 * tend towards setting the same matrix repeatedly for some reason.
2359 * From here on we assume that the new matrix is different, wherever it matters.
2361 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2362 TRACE("The app is setting the same matrix over again\n");
2365 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2369 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2370 where ViewMat = Camera space, WorldMat = world space.
2372 In OpenGL, camera and world space is combined into GL_MODELVIEW
2373 matrix. The Projection matrix stay projection matrix.
2376 /* Capture the times we can just ignore the change for now */
2377 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2378 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2379 /* Handled by the state manager */
2382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2386 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2388 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2389 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2393 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2394 WINED3DMATRIX *mat = NULL;
2397 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2398 * below means it will be recorded in a state block change, but it
2399 * works regardless where it is recorded.
2400 * If this is found to be wrong, change to StateBlock.
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2405 if (State < HIGHEST_TRANSFORMSTATE)
2407 mat = &This->updateStateBlock->transforms[State];
2409 FIXME("Unhandled transform state!!\n");
2412 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2414 /* Apply change via set transform - will reapply to eg. lights this way */
2415 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2421 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2422 you can reference any indexes you want as long as that number max are enabled at any
2423 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2424 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2425 but when recording, just build a chain pretty much of commands to be replayed. */
2427 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2429 PLIGHTINFOEL *object, *temp;
2431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2432 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2434 /* If recording state block, just add to end of lights chain */
2435 if (This->isRecordingState) {
2436 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2437 if (NULL == object) {
2438 return WINED3DERR_OUTOFVIDEOMEMORY;
2440 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2441 object->OriginalIndex = Index;
2442 object->glIndex = -1;
2443 object->changed = TRUE;
2445 /* Add to the END of the chain of lights changes to be replayed */
2446 if (This->updateStateBlock->lights == NULL) {
2447 This->updateStateBlock->lights = object;
2449 temp = This->updateStateBlock->lights;
2450 while (temp->next != NULL) temp=temp->next;
2451 temp->next = object;
2453 TRACE("Recording... not performing anything more\n");
2457 /* Ok, not recording any longer so do real work */
2458 object = This->stateBlock->lights;
2459 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2461 /* If we didn't find it in the list of lights, time to add it */
2462 if (object == NULL) {
2463 PLIGHTINFOEL *insertAt,*prevPos;
2465 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2466 if (NULL == object) {
2467 return WINED3DERR_OUTOFVIDEOMEMORY;
2469 object->OriginalIndex = Index;
2470 object->glIndex = -1;
2472 /* Add it to the front of list with the idea that lights will be changed as needed
2473 BUT after any lights currently assigned GL indexes */
2474 insertAt = This->stateBlock->lights;
2476 while (insertAt != NULL && insertAt->glIndex != -1) {
2478 insertAt = insertAt->next;
2481 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2482 This->stateBlock->lights = object;
2483 } else if (insertAt == NULL) { /* End of list */
2484 prevPos->next = object;
2485 object->prev = prevPos;
2486 } else { /* Middle of chain */
2487 if (prevPos == NULL) {
2488 This->stateBlock->lights = object;
2490 prevPos->next = object;
2492 object->prev = prevPos;
2493 object->next = insertAt;
2494 insertAt->prev = object;
2498 /* Initialize the object */
2499 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,
2500 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2501 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2502 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2503 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2504 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2505 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2507 /* Save away the information */
2508 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2510 switch (pLight->Type) {
2511 case WINED3DLIGHT_POINT:
2513 object->lightPosn[0] = pLight->Position.x;
2514 object->lightPosn[1] = pLight->Position.y;
2515 object->lightPosn[2] = pLight->Position.z;
2516 object->lightPosn[3] = 1.0f;
2517 object->cutoff = 180.0f;
2521 case WINED3DLIGHT_DIRECTIONAL:
2523 object->lightPosn[0] = -pLight->Direction.x;
2524 object->lightPosn[1] = -pLight->Direction.y;
2525 object->lightPosn[2] = -pLight->Direction.z;
2526 object->lightPosn[3] = 0.0;
2527 object->exponent = 0.0f;
2528 object->cutoff = 180.0f;
2531 case WINED3DLIGHT_SPOT:
2533 object->lightPosn[0] = pLight->Position.x;
2534 object->lightPosn[1] = pLight->Position.y;
2535 object->lightPosn[2] = pLight->Position.z;
2536 object->lightPosn[3] = 1.0;
2539 object->lightDirn[0] = pLight->Direction.x;
2540 object->lightDirn[1] = pLight->Direction.y;
2541 object->lightDirn[2] = pLight->Direction.z;
2542 object->lightDirn[3] = 1.0;
2545 * opengl-ish and d3d-ish spot lights use too different models for the
2546 * light "intensity" as a function of the angle towards the main light direction,
2547 * so we only can approximate very roughly.
2548 * however spot lights are rather rarely used in games (if ever used at all).
2549 * furthermore if still used, probably nobody pays attention to such details.
2551 if (pLight->Falloff == 0) {
2554 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2556 if (rho < 0.0001) rho = 0.0001f;
2557 object->exponent = -0.3/log(cos(rho/2));
2558 if (object->exponent > 128.0) {
2559 object->exponent = 128.0;
2561 object->cutoff = pLight->Phi*90/M_PI;
2567 FIXME("Unrecognized light type %d\n", pLight->Type);
2570 /* Update the live definitions if the light is currently assigned a glIndex */
2571 if (object->glIndex != -1) {
2572 setup_light(iface, object->glIndex, object);
2577 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2578 PLIGHTINFOEL *lightInfo = NULL;
2579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2582 /* Locate the light in the live lights */
2583 lightInfo = This->stateBlock->lights;
2584 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2586 if (lightInfo == NULL) {
2587 TRACE("Light information requested but light not defined\n");
2588 return WINED3DERR_INVALIDCALL;
2591 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2596 * Get / Set Light Enable
2597 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2599 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2600 PLIGHTINFOEL *lightInfo = NULL;
2601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2602 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2604 /* Tests show true = 128...not clear why */
2606 Enable = Enable? 128: 0;
2608 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2609 if (This->isRecordingState) {
2610 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2611 if (NULL == lightInfo) {
2612 return WINED3DERR_OUTOFVIDEOMEMORY;
2614 lightInfo->OriginalIndex = Index;
2615 lightInfo->glIndex = -1;
2616 lightInfo->enabledChanged = TRUE;
2617 lightInfo->lightEnabled = Enable;
2619 /* Add to the END of the chain of lights changes to be replayed */
2620 if (This->updateStateBlock->lights == NULL) {
2621 This->updateStateBlock->lights = lightInfo;
2623 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2624 while (temp->next != NULL) temp=temp->next;
2625 temp->next = lightInfo;
2627 TRACE("Recording... not performing anything more\n");
2631 /* Not recording... So, locate the light in the live lights */
2632 lightInfo = This->stateBlock->lights;
2633 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2635 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2636 if (lightInfo == NULL) {
2638 TRACE("Light enabled requested but light not defined, so defining one!\n");
2639 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2641 /* Search for it again! Should be fairly quick as near head of list */
2642 lightInfo = This->stateBlock->lights;
2643 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2644 if (lightInfo == NULL) {
2645 FIXME("Adding default lights has failed dismally\n");
2646 return WINED3DERR_INVALIDCALL;
2650 /* OK, we now have a light... */
2653 /* If we are disabling it, check it was enabled, and
2654 still only do something if it has assigned a glIndex (which it should have!) */
2655 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2656 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2658 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2659 checkGLcall("glDisable GL_LIGHT0+Index");
2662 TRACE("Nothing to do as light was not enabled\n");
2664 lightInfo->lightEnabled = Enable;
2667 /* We are enabling it. If it is enabled, it's really simple */
2668 if (lightInfo->lightEnabled) {
2670 TRACE("Nothing to do as light was enabled\n");
2672 /* If it already has a glIndex, it's still simple */
2673 } else if (lightInfo->glIndex != -1) {
2674 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2675 lightInfo->lightEnabled = Enable;
2677 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2678 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2681 /* Otherwise got to find space - lights are ordered gl indexes first */
2683 PLIGHTINFOEL *bsf = NULL;
2684 PLIGHTINFOEL *pos = This->stateBlock->lights;
2685 PLIGHTINFOEL *prev = NULL;
2689 /* Try to minimize changes as much as possible */
2690 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2692 /* Try to remember which index can be replaced if necessary */
2693 if (bsf==NULL && !pos->lightEnabled) {
2694 /* Found a light we can replace, save as best replacement */
2698 /* Step to next space */
2704 /* If we have too many active lights, fail the call */
2705 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2706 FIXME("Program requests too many concurrent lights\n");
2707 return WINED3DERR_INVALIDCALL;
2709 /* If we have allocated all lights, but not all are enabled,
2710 reuse one which is not enabled */
2711 } else if (Index == This->maxConcurrentLights) {
2712 /* use bsf - Simply swap the new light and the BSF one */
2713 PLIGHTINFOEL *bsfNext = bsf->next;
2714 PLIGHTINFOEL *bsfPrev = bsf->prev;
2717 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2718 if (bsf->prev != NULL) {
2719 bsf->prev->next = lightInfo;
2721 This->stateBlock->lights = lightInfo;
2724 /* If not side by side, lots of chains to update */
2725 if (bsf->next != lightInfo) {
2726 lightInfo->prev->next = bsf;
2727 bsf->next->prev = lightInfo;
2728 bsf->next = lightInfo->next;
2729 bsf->prev = lightInfo->prev;
2730 lightInfo->next = bsfNext;
2731 lightInfo->prev = bsfPrev;
2735 bsf->prev = lightInfo;
2736 bsf->next = lightInfo->next;
2737 lightInfo->next = bsf;
2738 lightInfo->prev = bsfPrev;
2743 glIndex = bsf->glIndex;
2745 lightInfo->glIndex = glIndex;
2746 lightInfo->lightEnabled = Enable;
2748 /* Finally set up the light in gl itself */
2749 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2751 setup_light(iface, glIndex, lightInfo);
2752 glEnable(GL_LIGHT0 + glIndex);
2753 checkGLcall("glEnable GL_LIGHT0 new setup");
2756 /* If we reached the end of the allocated lights, with space in the
2757 gl lights, setup a new light */
2758 } else if (pos->glIndex == -1) {
2760 /* We reached the end of the allocated gl lights, so already
2761 know the index of the next one! */
2763 lightInfo->glIndex = glIndex;
2764 lightInfo->lightEnabled = Enable;
2766 /* In an ideal world, it's already in the right place */
2767 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2768 /* No need to move it */
2770 /* Remove this light from the list */
2771 lightInfo->prev->next = lightInfo->next;
2772 if (lightInfo->next != NULL) {
2773 lightInfo->next->prev = lightInfo->prev;
2776 /* Add in at appropriate place (inbetween prev and pos) */
2777 lightInfo->prev = prev;
2778 lightInfo->next = pos;
2780 This->stateBlock->lights = lightInfo;
2782 prev->next = lightInfo;
2785 pos->prev = lightInfo;
2789 /* Finally set up the light in gl itself */
2790 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
2792 setup_light(iface, glIndex, lightInfo);
2793 glEnable(GL_LIGHT0 + glIndex);
2794 checkGLcall("glEnable GL_LIGHT0 new setup");
2803 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2805 PLIGHTINFOEL *lightInfo = NULL;
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 TRACE("(%p) : for idx(%d)\n", This, Index);
2809 /* Locate the light in the live lights */
2810 lightInfo = This->stateBlock->lights;
2811 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2813 if (lightInfo == NULL) {
2814 TRACE("Light enabled state requested but light not defined\n");
2815 return WINED3DERR_INVALIDCALL;
2817 *pEnable = lightInfo->lightEnabled;
2822 * Get / Set Clip Planes
2824 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2828 /* Validate Index */
2829 if (Index >= GL_LIMITS(clipplanes)) {
2830 TRACE("Application has requested clipplane this device doesn't support\n");
2831 return WINED3DERR_INVALIDCALL;
2834 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2835 This->updateStateBlock->set.clipplane[Index] = TRUE;
2836 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2837 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2838 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2839 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2841 /* Handle recording of state blocks */
2842 if (This->isRecordingState) {
2843 TRACE("Recording... not performing anything\n");
2851 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2852 glMatrixMode(GL_MODELVIEW);
2854 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2856 TRACE("Clipplane [%f,%f,%f,%f]\n",
2857 This->updateStateBlock->clipplane[Index][0],
2858 This->updateStateBlock->clipplane[Index][1],
2859 This->updateStateBlock->clipplane[Index][2],
2860 This->updateStateBlock->clipplane[Index][3]);
2861 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2862 checkGLcall("glClipPlane");
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 TRACE("(%p) : for idx %d\n", This, Index);
2874 /* Validate Index */
2875 if (Index >= GL_LIMITS(clipplanes)) {
2876 TRACE("Application has requested clipplane this device doesn't support\n");
2877 return WINED3DERR_INVALIDCALL;
2880 pPlane[0] = This->stateBlock->clipplane[Index][0];
2881 pPlane[1] = This->stateBlock->clipplane[Index][1];
2882 pPlane[2] = This->stateBlock->clipplane[Index][2];
2883 pPlane[3] = This->stateBlock->clipplane[Index][3];
2888 * Get / Set Clip Plane Status
2889 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2891 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 FIXME("(%p) : stub\n", This);
2894 if (NULL == pClipStatus) {
2895 return WINED3DERR_INVALIDCALL;
2897 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2898 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2902 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 FIXME("(%p) : stub\n", This);
2905 if (NULL == pClipStatus) {
2906 return WINED3DERR_INVALIDCALL;
2908 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2909 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2914 * Get / Set Material
2916 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2919 This->updateStateBlock->changed.material = TRUE;
2920 This->updateStateBlock->set.material = TRUE;
2921 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2923 /* Handle recording of state blocks */
2924 if (This->isRecordingState) {
2925 TRACE("Recording... not performing anything\n");
2930 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2931 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2932 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2933 pMaterial->Ambient.b, pMaterial->Ambient.a);
2934 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2935 pMaterial->Specular.b, pMaterial->Specular.a);
2936 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2937 pMaterial->Emissive.b, pMaterial->Emissive.a);
2938 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2940 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2941 checkGLcall("glMaterialfv(GL_AMBIENT)");
2942 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2943 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2945 /* Only change material color if specular is enabled, otherwise it is set to black */
2946 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2947 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2948 checkGLcall("glMaterialfv(GL_SPECULAR");
2950 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2951 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2952 checkGLcall("glMaterialfv(GL_SPECULAR");
2954 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2955 checkGLcall("glMaterialfv(GL_EMISSION)");
2956 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2957 checkGLcall("glMaterialf(GL_SHININESS");
2963 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2965 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2966 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2967 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2968 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2969 pMaterial->Ambient.b, pMaterial->Ambient.a);
2970 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2971 pMaterial->Specular.b, pMaterial->Specular.a);
2972 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2973 pMaterial->Emissive.b, pMaterial->Emissive.a);
2974 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2982 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2983 UINT BaseVertexIndex) {
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 IWineD3DIndexBuffer *oldIdxs;
2986 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2988 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2989 oldIdxs = This->updateStateBlock->pIndexData;
2991 This->updateStateBlock->changed.indices = TRUE;
2992 This->updateStateBlock->set.indices = TRUE;
2993 This->updateStateBlock->pIndexData = pIndexData;
2994 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2996 /* Handle recording of state blocks */
2997 if (This->isRecordingState) {
2998 TRACE("Recording... not performing anything\n");
3002 /* So far only the base vertex index is tracked */
3003 if(BaseVertexIndex != oldBaseIndex) {
3004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3009 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 *ppIndexData = This->stateBlock->pIndexData;
3014 /* up ref count on ppindexdata */
3016 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3017 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3018 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3020 TRACE("(%p) No index data set\n", This);
3022 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3027 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3028 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 TRACE("(%p)->(%d)\n", This, BaseIndex);
3032 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3033 TRACE("Application is setting the old value over, nothing to do\n");
3037 This->updateStateBlock->baseVertexIndex = BaseIndex;
3039 if (This->isRecordingState) {
3040 TRACE("Recording... not performing anything\n");
3043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3048 * Get / Set Viewports
3050 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 TRACE("(%p)\n", This);
3054 This->updateStateBlock->changed.viewport = TRUE;
3055 This->updateStateBlock->set.viewport = TRUE;
3056 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3058 /* Handle recording of state blocks */
3059 if (This->isRecordingState) {
3060 TRACE("Recording... not performing anything\n");
3064 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3065 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3072 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 TRACE("(%p)\n", This);
3075 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3080 * Get / Set Render States
3081 * TODO: Verify against dx9 definitions
3083 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 DWORD oldValue = This->stateBlock->renderState[State];
3088 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3090 This->updateStateBlock->changed.renderState[State] = TRUE;
3091 This->updateStateBlock->set.renderState[State] = TRUE;
3092 This->updateStateBlock->renderState[State] = Value;
3094 /* Handle recording of state blocks */
3095 if (This->isRecordingState) {
3096 TRACE("Recording... not performing anything\n");
3100 /* Compared here and not before the assignment to allow proper stateblock recording */
3101 if(Value == oldValue) {
3102 TRACE("Application is setting the old value over, nothing to do\n");
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3110 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3113 *pValue = This->stateBlock->renderState[State];
3118 * Get / Set Sampler States
3119 * TODO: Verify against dx9 definitions
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3127 * SetSampler is designed to allow for more than the standard up to 8 textures
3128 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3129 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3131 * http://developer.nvidia.com/object/General_FAQ.html#t6
3133 * There are two new settings for GForce
3135 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3136 * and the texture one:
3137 * GL_MAX_TEXTURE_COORDS_ARB.
3138 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3140 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
3141 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3142 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3143 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3144 return WINED3DERR_INVALIDCALL;
3147 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3148 debug_d3dsamplerstate(Type), Type, Value);
3149 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3150 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3151 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3153 /* Handle recording of state blocks */
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3159 if(oldValue == Value) {
3160 TRACE("Application is setting the old value over, nothing to do\n");
3164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3169 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 /** TODO: check that sampler is in range **/
3172 *Value = This->stateBlock->samplerState[Sampler][Type];
3173 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3178 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 This->updateStateBlock->set.scissorRect = TRUE;
3184 This->updateStateBlock->changed.scissorRect = TRUE;
3185 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
3187 if(This->isRecordingState) {
3188 TRACE("Recording... not performing anything\n");
3192 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3193 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3194 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3196 winHeight = windowRect.bottom - windowRect.top;
3197 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3198 pRect->right - pRect->left, pRect->bottom - pRect->top);
3200 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3201 checkGLcall("glScissor");
3207 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3211 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3215 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3217 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3219 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3221 This->updateStateBlock->vertexDecl = pDecl;
3222 This->updateStateBlock->changed.vertexDecl = TRUE;
3223 This->updateStateBlock->set.vertexDecl = TRUE;
3225 if (This->isRecordingState) {
3226 TRACE("Recording... not performing anything\n");
3228 } else if(pDecl == oldDecl) {
3229 /* Checked after the assignment to allow proper stateblock recording */
3230 TRACE("Application is setting the old declaration over, nothing to do\n");
3234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3238 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3241 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3243 *ppDecl = This->stateBlock->vertexDecl;
3244 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3248 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3250 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3252 This->updateStateBlock->vertexShader = pShader;
3253 This->updateStateBlock->changed.vertexShader = TRUE;
3254 This->updateStateBlock->set.vertexShader = TRUE;
3256 if (This->isRecordingState) {
3257 TRACE("Recording... not performing anything\n");
3259 } else if(oldShader == pShader) {
3260 /* Checked here to allow proper stateblock recording */
3261 TRACE("App is setting the old shader over, nothing to do\n");
3265 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 if (NULL == ppShader) {
3276 return WINED3DERR_INVALIDCALL;
3278 *ppShader = This->stateBlock->vertexShader;
3279 if( NULL != *ppShader)
3280 IWineD3DVertexShader_AddRef(*ppShader);
3282 TRACE("(%p) : returning %p\n", This, *ppShader);
3286 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3287 IWineD3DDevice *iface,
3289 CONST BOOL *srcData,
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 int i, cnt = min(count, MAX_CONST_B - start);
3295 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3296 iface, srcData, start, count);
3298 if (srcData == NULL || cnt < 0)
3299 return WINED3DERR_INVALIDCALL;
3301 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3302 for (i = 0; i < cnt; i++)
3303 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3305 for (i = start; i < cnt + start; ++i) {
3306 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3307 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3316 IWineD3DDevice *iface,
3321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 int cnt = min(count, MAX_CONST_B - start);
3324 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3325 iface, dstData, start, count);
3327 if (dstData == NULL || cnt < 0)
3328 return WINED3DERR_INVALIDCALL;
3330 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3334 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3335 IWineD3DDevice *iface,
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3341 int i, cnt = min(count, MAX_CONST_I - start);
3343 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3344 iface, srcData, start, count);
3346 if (srcData == NULL || cnt < 0)
3347 return WINED3DERR_INVALIDCALL;
3349 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3350 for (i = 0; i < cnt; i++)
3351 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3352 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3354 for (i = start; i < cnt + start; ++i) {
3355 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3356 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3364 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3365 IWineD3DDevice *iface,
3370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3371 int cnt = min(count, MAX_CONST_I - start);
3373 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3374 iface, dstData, start, count);
3376 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3377 return WINED3DERR_INVALIDCALL;
3379 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3383 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3384 IWineD3DDevice *iface,
3386 CONST float *srcData,
3389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3390 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3392 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3393 iface, srcData, start, count);
3395 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3396 return WINED3DERR_INVALIDCALL;
3398 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3399 for (i = 0; i < cnt; i++)
3400 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3401 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3403 for (i = start; i < cnt + start; ++i) {
3404 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3405 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3407 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3408 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3410 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3418 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3419 IWineD3DDevice *iface,
3424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3425 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3427 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3428 iface, dstData, start, count);
3430 if (dstData == NULL || cnt < 0)
3431 return WINED3DERR_INVALIDCALL;
3433 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3437 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3439 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3444 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3446 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3447 * it is never called.
3450 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3451 * that would be really messy and require shader recompilation
3452 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3453 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3454 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3455 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3457 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3458 if(This->oneToOneTexUnitMap) {
3459 TRACE("Not touching 1:1 map\n");
3462 TRACE("Restoring 1:1 texture unit mapping\n");
3463 /* Restore a 1:1 mapping */
3464 for(i = 0; i < MAX_SAMPLERS; i++) {
3465 if(This->texUnitMap[i] != i) {
3466 This->texUnitMap[i] = i;
3467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3468 markTextureStagesDirty(This, i);
3471 This->oneToOneTexUnitMap = TRUE;
3474 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3475 * First, see if we can succeed at all
3478 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3479 if(This->stateBlock->textures[i] == NULL) tex++;
3482 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3483 FIXME("Too many bound textures to support the combiner settings\n");
3487 /* Now work out the mapping */
3489 This->oneToOneTexUnitMap = FALSE;
3490 WARN("Non 1:1 mapping UNTESTED!\n");
3491 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3492 /* Skip NULL textures */
3493 if (!This->stateBlock->textures[i]) {
3494 /* Map to -1, so the check below doesn't fail if a non-NULL
3495 * texture is set on this stage */
3496 TRACE("Mapping texture stage %d to -1\n", i);
3497 This->texUnitMap[i] = -1;
3502 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3503 if(This->texUnitMap[i] != tex) {
3504 This->texUnitMap[i] = tex;
3505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3506 markTextureStagesDirty(This, i);
3514 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3516 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3517 This->updateStateBlock->pixelShader = pShader;
3518 This->updateStateBlock->changed.pixelShader = TRUE;
3519 This->updateStateBlock->set.pixelShader = TRUE;
3521 /* Handle recording of state blocks */
3522 if (This->isRecordingState) {
3523 TRACE("Recording... not performing anything\n");
3526 if (This->isRecordingState) {
3527 TRACE("Recording... not performing anything\n");
3531 if(pShader == oldShader) {
3532 TRACE("App is setting the old pixel shader over, nothing to do\n");
3536 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3539 /* Rebuild the texture unit mapping if nvrc's are supported */
3540 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3541 IWineD3DDeviceImpl_FindTexUnitMap(This);
3547 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 if (NULL == ppShader) {
3551 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3552 return WINED3DERR_INVALIDCALL;
3555 *ppShader = This->stateBlock->pixelShader;
3556 if (NULL != *ppShader) {
3557 IWineD3DPixelShader_AddRef(*ppShader);
3559 TRACE("(%p) : returning %p\n", This, *ppShader);
3563 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3564 IWineD3DDevice *iface,
3566 CONST BOOL *srcData,
3569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3570 int i, cnt = min(count, MAX_CONST_B - start);
3572 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3573 iface, srcData, start, count);
3575 if (srcData == NULL || cnt < 0)
3576 return WINED3DERR_INVALIDCALL;
3578 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3579 for (i = 0; i < cnt; i++)
3580 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3582 for (i = start; i < cnt + start; ++i) {
3583 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3584 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3592 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3593 IWineD3DDevice *iface,
3598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3599 int cnt = min(count, MAX_CONST_B - start);
3601 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3602 iface, dstData, start, count);
3604 if (dstData == NULL || cnt < 0)
3605 return WINED3DERR_INVALIDCALL;
3607 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3611 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3612 IWineD3DDevice *iface,
3617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3618 int i, cnt = min(count, MAX_CONST_I - start);
3620 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3621 iface, srcData, start, count);
3623 if (srcData == NULL || cnt < 0)
3624 return WINED3DERR_INVALIDCALL;
3626 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3627 for (i = 0; i < cnt; i++)
3628 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3629 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3631 for (i = start; i < cnt + start; ++i) {
3632 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3633 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3641 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3642 IWineD3DDevice *iface,
3647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3648 int cnt = min(count, MAX_CONST_I - start);
3650 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3651 iface, dstData, start, count);
3653 if (dstData == NULL || cnt < 0)
3654 return WINED3DERR_INVALIDCALL;
3656 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3660 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3661 IWineD3DDevice *iface,
3663 CONST float *srcData,
3666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3667 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3669 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3670 iface, srcData, start, count);
3672 if (srcData == NULL || cnt < 0)
3673 return WINED3DERR_INVALIDCALL;
3675 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3676 for (i = 0; i < cnt; i++)
3677 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3678 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3680 for (i = start; i < cnt + start; ++i) {
3681 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3682 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3684 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3685 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3687 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3695 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3696 IWineD3DDevice *iface,
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3702 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3704 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3705 iface, dstData, start, count);
3707 if (dstData == NULL || cnt < 0)
3708 return WINED3DERR_INVALIDCALL;
3710 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3714 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3716 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3717 char *dest_ptr, *dest_conv = NULL;
3719 DWORD DestFVF = dest->fvf;
3721 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3725 if (SrcFVF & WINED3DFVF_NORMAL) {
3726 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3729 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3730 ERR("Source has no position mask\n");
3731 return WINED3DERR_INVALIDCALL;
3734 /* We might access VBOs from this code, so hold the lock */
3737 if (dest->resource.allocatedMemory == NULL) {
3738 /* This may happen if we do direct locking into a vbo. Unlikely,
3739 * but theoretically possible(ddraw processvertices test)
3741 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3742 if(!dest->resource.allocatedMemory) {
3744 ERR("Out of memory\n");
3745 return E_OUTOFMEMORY;
3749 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3750 checkGLcall("glBindBufferARB");
3751 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3753 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3755 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3756 checkGLcall("glUnmapBufferARB");
3760 /* Get a pointer into the destination vbo(create one if none exists) and
3761 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3763 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3768 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3769 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3771 ERR("glMapBuffer failed\n");
3772 /* Continue without storing converted vertices */
3777 * a) WINED3DRS_CLIPPING is enabled
3778 * b) WINED3DVOP_CLIP is passed
3780 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3781 static BOOL warned = FALSE;
3783 * The clipping code is not quite correct. Some things need
3784 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3785 * so disable clipping for now.
3786 * (The graphics in Half-Life are broken, and my processvertices
3787 * test crashes with IDirect3DDevice3)
3793 FIXME("Clipping is broken and disabled for now\n");
3795 } else doClip = FALSE;
3796 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3798 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3801 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3804 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3805 WINED3DTS_PROJECTION,
3807 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3808 WINED3DTS_WORLDMATRIX(0),
3811 TRACE("View mat:\n");
3812 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);
3813 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);
3814 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);
3815 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);
3817 TRACE("Proj mat:\n");
3818 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);
3819 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);
3820 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);
3821 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);
3823 TRACE("World mat:\n");
3824 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);
3825 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);
3826 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);
3827 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);
3829 /* Get the viewport */
3830 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3831 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3832 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3834 multiply_matrix(&mat,&view_mat,&world_mat);
3835 multiply_matrix(&mat,&proj_mat,&mat);
3837 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3839 for (i = 0; i < dwCount; i+= 1) {
3840 unsigned int tex_index;
3842 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3843 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3844 /* The position first */
3846 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3848 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3850 /* Multiplication with world, view and projection matrix */
3851 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);
3852 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);
3853 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);
3854 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);
3856 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3858 /* WARNING: The following things are taken from d3d7 and were not yet checked
3859 * against d3d8 or d3d9!
3862 /* Clipping conditions: From
3863 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3865 * A vertex is clipped if it does not match the following requirements
3869 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3871 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3872 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3877 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3878 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3881 /* "Normal" viewport transformation (not clipped)
3882 * 1) The values are divided by rhw
3883 * 2) The y axis is negative, so multiply it with -1
3884 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3885 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3886 * 4) Multiply x with Width/2 and add Width/2
3887 * 5) The same for the height
3888 * 6) Add the viewpoint X and Y to the 2D coordinates and
3889 * The minimum Z value to z
3890 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3892 * Well, basically it's simply a linear transformation into viewport
3904 z *= vp.MaxZ - vp.MinZ;
3906 x += vp.Width / 2 + vp.X;
3907 y += vp.Height / 2 + vp.Y;
3912 /* That vertex got clipped
3913 * Contrary to OpenGL it is not dropped completely, it just
3914 * undergoes a different calculation.
3916 TRACE("Vertex got clipped\n");
3923 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3924 * outside of the main vertex buffer memory. That needs some more
3929 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3932 ( (float *) dest_ptr)[0] = x;
3933 ( (float *) dest_ptr)[1] = y;
3934 ( (float *) dest_ptr)[2] = z;
3935 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3937 dest_ptr += 3 * sizeof(float);
3939 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3940 dest_ptr += sizeof(float);
3945 ( (float *) dest_conv)[0] = x * w;
3946 ( (float *) dest_conv)[1] = y * w;
3947 ( (float *) dest_conv)[2] = z * w;
3948 ( (float *) dest_conv)[3] = w;
3950 dest_conv += 3 * sizeof(float);
3952 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3953 dest_conv += sizeof(float);
3957 if (DestFVF & WINED3DFVF_PSIZE) {
3958 dest_ptr += sizeof(DWORD);
3959 if(dest_conv) dest_conv += sizeof(DWORD);
3961 if (DestFVF & WINED3DFVF_NORMAL) {
3963 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3964 /* AFAIK this should go into the lighting information */
3965 FIXME("Didn't expect the destination to have a normal\n");
3966 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3968 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3972 if (DestFVF & WINED3DFVF_DIFFUSE) {
3974 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3976 static BOOL warned = FALSE;
3979 ERR("No diffuse color in source, but destination has one\n");
3983 *( (DWORD *) dest_ptr) = 0xffffffff;
3984 dest_ptr += sizeof(DWORD);
3987 *( (DWORD *) dest_conv) = 0xffffffff;
3988 dest_conv += sizeof(DWORD);
3992 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3994 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3995 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3996 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3997 dest_conv += sizeof(DWORD);
4002 if (DestFVF & WINED3DFVF_SPECULAR) {
4003 /* What's the color value in the feedback buffer? */
4005 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4007 static BOOL warned = FALSE;
4010 ERR("No specular color in source, but destination has one\n");
4014 *( (DWORD *) dest_ptr) = 0xFF000000;
4015 dest_ptr += sizeof(DWORD);
4018 *( (DWORD *) dest_conv) = 0xFF000000;
4019 dest_conv += sizeof(DWORD);
4023 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4025 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4026 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4027 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4028 dest_conv += sizeof(DWORD);
4033 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4035 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4036 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4038 ERR("No source texture, but destination requests one\n");
4039 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4040 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4043 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4045 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4052 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4053 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4060 #undef copy_and_next
4062 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4064 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4065 WineDirect3DVertexStridedData strided;
4066 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4069 WARN("NULL source vertex buffer\n");
4070 return WINED3DERR_INVALIDCALL;
4072 /* We don't need the source vbo because this buffer is only used as
4073 * a source for ProcessVertices. Avoid wasting resources by converting the
4074 * buffer and loading the VBO
4077 TRACE("Releasing the source vbo, it won't be needed\n");
4079 if(!SrcImpl->resource.allocatedMemory) {
4080 /* Rescue the data from the buffer */
4082 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4083 if(!SrcImpl->resource.allocatedMemory) {
4084 ERR("Out of memory\n");
4085 return E_OUTOFMEMORY;
4089 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4090 checkGLcall("glBindBufferARB");
4092 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4094 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4097 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4098 checkGLcall("glUnmapBufferARB");
4103 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4104 checkGLcall("glBindBufferARB");
4105 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4106 checkGLcall("glDeleteBuffersARB");
4112 memset(&strided, 0, sizeof(strided));
4113 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4115 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4119 * Get / Set Texture Stage States
4120 * TODO: Verify against dx9 definitions
4122 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4126 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4128 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4130 /* Reject invalid texture units */
4131 if (Stage >= GL_LIMITS(texture_stages)) {
4132 TRACE("Attempt to access invalid texture rejected\n");
4133 return WINED3DERR_INVALIDCALL;
4136 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4137 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4138 This->updateStateBlock->textureState[Stage][Type] = Value;
4140 if (This->isRecordingState) {
4141 TRACE("Recording... not performing anything\n");
4145 /* Checked after the assignments to allow proper stateblock recording */
4146 if(oldValue == Value) {
4147 TRACE("App is setting the old value over, nothing to do\n");
4151 if(Stage > This->stateBlock->lowest_disabled_stage &&
4152 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4153 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4154 * Changes in other states are important on disabled stages too
4159 if(Type == WINED3DTSS_COLOROP) {
4162 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4163 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4164 * they have to be disabled
4166 * The current stage is dirtified below.
4168 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4169 TRACE("Additionally dirtifying stage %d\n", i);
4170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4172 This->stateBlock->lowest_disabled_stage = Stage;
4173 TRACE("New lowest disabled: %d\n", Stage);
4174 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4175 /* Previously disabled stage enabled. Stages above it may need enabling
4176 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4177 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4179 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4182 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4183 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4186 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4189 This->stateBlock->lowest_disabled_stage = i;
4190 TRACE("New lowest disabled: %d\n", i);
4192 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4193 /* TODO: Built a stage -> texture unit mapping for register combiners */
4197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4199 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4200 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4201 * will call FindTexUnitMap too.
4203 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4204 IWineD3DDeviceImpl_FindTexUnitMap(This);
4209 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4211 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4212 *pValue = This->updateStateBlock->textureState[Stage][Type];
4219 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4222 IWineD3DBaseTexture *oldTexture;
4224 oldTexture = This->updateStateBlock->textures[Stage];
4225 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4227 #if 0 /* TODO: check so vertex textures */
4228 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4229 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4234 /* Reject invalid texture units */
4235 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4236 WARN("Attempt to access invalid texture rejected\n");
4237 return WINED3DERR_INVALIDCALL;
4240 if(pTexture != NULL) {
4241 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4243 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4244 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4245 return WINED3DERR_INVALIDCALL;
4247 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4250 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4251 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4253 This->updateStateBlock->set.textures[Stage] = TRUE;
4254 This->updateStateBlock->changed.textures[Stage] = TRUE;
4255 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4256 This->updateStateBlock->textures[Stage] = pTexture;
4258 /* Handle recording of state blocks */
4259 if (This->isRecordingState) {
4260 TRACE("Recording... not performing anything\n");
4264 if(oldTexture == pTexture) {
4265 TRACE("App is setting the same texture again, nothing to do\n");
4269 /** NOTE: MSDN says that setTexture increases the reference count,
4270 * and the the application nust set the texture back to null (or have a leaky application),
4271 * This means we should pass the refcount up to the parent
4272 *******************************/
4273 if (NULL != This->updateStateBlock->textures[Stage]) {
4274 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4275 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4277 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4278 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4279 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4280 * so the COLOROP and ALPHAOP have to be dirtified.
4282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4285 if(bindCount == 1) {
4286 new->baseTexture.sampler = Stage;
4288 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4292 if (NULL != oldTexture) {
4293 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4294 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4296 IWineD3DBaseTexture_Release(oldTexture);
4297 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4302 if(bindCount && old->baseTexture.sampler == Stage) {
4304 /* Have to do a search for the other sampler(s) where the texture is bound to
4305 * Shouldn't happen as long as apps bind a texture only to one stage
4307 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4308 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4309 if(This->updateStateBlock->textures[i] == oldTexture) {
4310 old->baseTexture.sampler = i;
4317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4319 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4320 * pixel shader is used
4322 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4323 IWineD3DDeviceImpl_FindTexUnitMap(This);
4329 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4331 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4333 /* Reject invalid texture units */
4334 if (Stage >= GL_LIMITS(sampler_stages)) {
4335 TRACE("Attempt to access invalid texture rejected\n");
4336 return WINED3DERR_INVALIDCALL;
4338 *ppTexture=This->stateBlock->textures[Stage];
4340 IWineD3DBaseTexture_AddRef(*ppTexture);
4348 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4349 IWineD3DSurface **ppBackBuffer) {
4350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4351 IWineD3DSwapChain *swapChain;
4354 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4356 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4357 if (hr == WINED3D_OK) {
4358 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4359 IWineD3DSwapChain_Release(swapChain);
4361 *ppBackBuffer = NULL;
4366 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 WARN("(%p) : stub, calling idirect3d for now\n", This);
4369 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4372 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4374 IWineD3DSwapChain *swapChain;
4377 if(iSwapChain > 0) {
4378 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4379 if (hr == WINED3D_OK) {
4380 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4381 IWineD3DSwapChain_Release(swapChain);
4383 FIXME("(%p) Error getting display mode\n", This);
4386 /* Don't read the real display mode,
4387 but return the stored mode instead. X11 can't change the color
4388 depth, and some apps are pretty angry if they SetDisplayMode from
4389 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4391 Also don't relay to the swapchain because with ddraw it's possible
4392 that there isn't a swapchain at all */
4393 pMode->Width = This->ddraw_width;
4394 pMode->Height = This->ddraw_height;
4395 pMode->Format = This->ddraw_format;
4396 pMode->RefreshRate = 0;
4403 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 TRACE("(%p)->(%p)\n", This, hWnd);
4407 This->ddraw_window = hWnd;
4411 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4413 TRACE("(%p)->(%p)\n", This, hWnd);
4415 *hWnd = This->ddraw_window;
4420 * Stateblock related functions
4423 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4425 IWineD3DStateBlockImpl *object;
4426 HRESULT temp_result;
4428 TRACE("(%p)\n", This);
4430 if (This->isRecordingState) {
4431 return WINED3DERR_INVALIDCALL;
4434 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4435 if (NULL == object ) {
4436 FIXME("(%p)Error allocating memory for stateblock\n", This);
4437 return E_OUTOFMEMORY;
4439 TRACE("(%p) created object %p\n", This, object);
4440 object->wineD3DDevice= This;
4441 /** FIXME: object->parent = parent; **/
4442 object->parent = NULL;
4443 object->blockType = WINED3DSBT_ALL;
4445 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4447 temp_result = allocate_shader_constants(object);
4448 if (WINED3D_OK != temp_result)
4451 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4452 This->updateStateBlock = object;
4453 This->isRecordingState = TRUE;
4455 TRACE("(%p) recording stateblock %p\n",This , object);
4459 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4462 if (!This->isRecordingState) {
4463 FIXME("(%p) not recording! returning error\n", This);
4464 *ppStateBlock = NULL;
4465 return WINED3DERR_INVALIDCALL;
4468 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4469 This->isRecordingState = FALSE;
4470 This->updateStateBlock = This->stateBlock;
4471 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4472 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4473 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4478 * Scene related functions
4480 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4481 /* At the moment we have no need for any functionality at the beginning
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 TRACE("(%p) : stub\n", This);
4488 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 TRACE("(%p)\n", This);
4492 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4494 checkGLcall("glFlush");
4496 TRACE("End Scene\n");
4497 /* If we're using FBOs this isn't needed */
4498 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4500 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4501 IUnknown *targetContainer = NULL;
4502 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4503 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4504 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4505 /** always dirtify for now. we must find a better way to see that surface have been modified
4506 (Modifications should will only occur via draw-primitive, but we do need better locking
4507 switching to render-to-texture should remove the overhead though.
4509 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4510 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4511 IWineD3DSurface_PreLoad(This->render_targets[0]);
4512 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4513 IUnknown_Release(targetContainer);
4516 This->sceneEnded = TRUE;
4521 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4522 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4523 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 IWineD3DSwapChain *swapChain = NULL;
4527 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4529 TRACE("(%p) Presenting the frame\n", This);
4531 for(i = 0 ; i < swapchains ; i ++) {
4533 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4534 TRACE("presentinng chain %d, %p\n", i, swapChain);
4535 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4536 IWineD3DSwapChain_Release(swapChain);
4542 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4543 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4546 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4547 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4548 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4549 GLbitfield glMask = 0;
4550 GLboolean old_ztest;
4551 GLfloat old_z_clear_value;
4552 GLint old_stencil_clear_value;
4553 GLfloat old_color_clear_value[4];
4555 CONST WINED3DRECT* curRect;
4557 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4558 Count, pRects, Flags, Z, Stencil);
4562 glEnable(GL_SCISSOR_TEST);
4563 checkGLcall("glEnable GL_SCISSOR_TEST");
4565 if (Count > 0 && pRects) {
4571 /* Only set the values up once, as they are not changing */
4572 if (Flags & WINED3DCLEAR_STENCIL) {
4573 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4574 glClearStencil(Stencil);
4575 checkGLcall("glClearStencil");
4576 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4577 glStencilMask(0xFFFFFFFF);
4580 if (Flags & WINED3DCLEAR_ZBUFFER) {
4581 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4582 glDepthMask(GL_TRUE);
4583 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4585 checkGLcall("glClearDepth");
4586 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4589 if (Flags & WINED3DCLEAR_TARGET) {
4590 TRACE("Clearing screen with glClear to color %x\n", Color);
4591 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4592 glClearColor(D3DCOLOR_R(Color),
4596 checkGLcall("glClearColor");
4598 /* Clear ALL colors! */
4599 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4600 glMask = glMask | GL_COLOR_BUFFER_BIT;
4603 /* Now process each rect in turn */
4604 for (i = 0; i < Count || i == 0; i++) {
4607 /* Note gl uses lower left, width/height */
4608 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4609 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4610 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4611 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4612 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4613 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4614 checkGLcall("glScissor");
4616 glScissor(This->stateBlock->viewport.X,
4617 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4618 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4619 This->stateBlock->viewport.Width,
4620 This->stateBlock->viewport.Height);
4621 checkGLcall("glScissor");
4624 /* Clear the selected rectangle (or full screen) */
4626 checkGLcall("glClear");
4628 /* Step to the next rectangle */
4629 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4632 /* Restore the old values (why..?) */
4633 if (Flags & WINED3DCLEAR_STENCIL) {
4634 glClearStencil(old_stencil_clear_value);
4635 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4637 if (Flags & WINED3DCLEAR_ZBUFFER) {
4638 glDepthMask(old_ztest);
4639 glClearDepth(old_z_clear_value);
4641 if (Flags & WINED3DCLEAR_TARGET) {
4642 glClearColor(old_color_clear_value[0],
4643 old_color_clear_value[1],
4644 old_color_clear_value[2],
4645 old_color_clear_value[3]);
4646 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4647 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4648 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4649 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4652 glDisable(GL_SCISSOR_TEST);
4653 checkGLcall("glDisable");
4662 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4663 UINT PrimitiveCount) {
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 This->stateBlock->streamIsUP = FALSE;
4668 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4669 debug_d3dprimitivetype(PrimitiveType),
4670 StartVertex, PrimitiveCount);
4672 if(This->stateBlock->loadBaseVertexIndex != 0) {
4673 This->stateBlock->loadBaseVertexIndex = 0;
4674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4676 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4677 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4678 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4682 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4683 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4684 WINED3DPRIMITIVETYPE PrimitiveType,
4685 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4689 IWineD3DIndexBuffer *pIB;
4690 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4692 pIB = This->stateBlock->pIndexData;
4693 This->stateBlock->streamIsUP = FALSE;
4695 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4696 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4697 minIndex, NumVertices, startIndex, primCount);
4699 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4700 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4706 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4707 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4711 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4712 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4717 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4718 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4719 UINT VertexStreamZeroStride) {
4720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4723 debug_d3dprimitivetype(PrimitiveType),
4724 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4726 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4727 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4728 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4729 This->stateBlock->streamIsUP = TRUE;
4730 This->stateBlock->loadBaseVertexIndex = 0;
4732 /* TODO: Only mark dirty if drawing from a different UP address */
4733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4735 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4736 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4738 /* MSDN specifies stream zero settings must be set to NULL */
4739 This->stateBlock->streamStride[0] = 0;
4740 This->stateBlock->streamSource[0] = NULL;
4742 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4743 * the new stream sources or use UP drawing again
4748 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4749 UINT MinVertexIndex, UINT NumVertices,
4750 UINT PrimitiveCount, CONST void* pIndexData,
4751 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4752 UINT VertexStreamZeroStride) {
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4756 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4757 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4758 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4759 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4761 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4767 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4768 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4769 This->stateBlock->streamIsUP = TRUE;
4770 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4772 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4773 This->stateBlock->baseVertexIndex = 0;
4774 This->stateBlock->loadBaseVertexIndex = 0;
4775 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4778 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4780 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4781 This->stateBlock->streamSource[0] = NULL;
4782 This->stateBlock->streamStride[0] = 0;
4783 This->stateBlock->pIndexData = NULL;
4784 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4785 * SetStreamSource to specify a vertex buffer
4791 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4794 /* Mark the state dirty until we have nicer tracking
4795 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4799 This->stateBlock->baseVertexIndex = 0;
4800 This->up_strided = DrawPrimStrideData;
4801 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4802 This->up_strided = NULL;
4805 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4806 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 HRESULT hr = WINED3D_OK;
4809 WINED3DRESOURCETYPE sourceType;
4810 WINED3DRESOURCETYPE destinationType;
4813 /* TODO: think about moving the code into IWineD3DBaseTexture */
4815 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4817 /* verify that the source and destination textures aren't NULL */
4818 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4819 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4820 This, pSourceTexture, pDestinationTexture);
4821 hr = WINED3DERR_INVALIDCALL;
4824 if (pSourceTexture == pDestinationTexture) {
4825 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4826 This, pSourceTexture, pDestinationTexture);
4827 hr = WINED3DERR_INVALIDCALL;
4829 /* Verify that the source and destination textures are the same type */
4830 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4831 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4833 if (sourceType != destinationType) {
4834 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4836 hr = WINED3DERR_INVALIDCALL;
4839 /* check that both textures have the identical numbers of levels */
4840 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4841 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4842 hr = WINED3DERR_INVALIDCALL;
4845 if (WINED3D_OK == hr) {
4847 /* Make sure that the destination texture is loaded */
4848 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4850 /* Update every surface level of the texture */
4851 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4853 switch (sourceType) {
4854 case WINED3DRTYPE_TEXTURE:
4856 IWineD3DSurface *srcSurface;
4857 IWineD3DSurface *destSurface;
4859 for (i = 0 ; i < levels ; ++i) {
4860 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4861 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4862 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4863 IWineD3DSurface_Release(srcSurface);
4864 IWineD3DSurface_Release(destSurface);
4865 if (WINED3D_OK != hr) {
4866 WARN("(%p) : Call to update surface failed\n", This);
4872 case WINED3DRTYPE_CUBETEXTURE:
4874 IWineD3DSurface *srcSurface;
4875 IWineD3DSurface *destSurface;
4876 WINED3DCUBEMAP_FACES faceType;
4878 for (i = 0 ; i < levels ; ++i) {
4879 /* Update each cube face */
4880 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4881 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4882 if (WINED3D_OK != hr) {
4883 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4885 TRACE("Got srcSurface %p\n", srcSurface);
4887 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4888 if (WINED3D_OK != hr) {
4889 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4891 TRACE("Got desrSurface %p\n", destSurface);
4893 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4894 IWineD3DSurface_Release(srcSurface);
4895 IWineD3DSurface_Release(destSurface);
4896 if (WINED3D_OK != hr) {
4897 WARN("(%p) : Call to update surface failed\n", This);
4904 #if 0 /* TODO: Add support for volume textures */
4905 case WINED3DRTYPE_VOLUMETEXTURE:
4907 IWineD3DVolume srcVolume = NULL;
4908 IWineD3DSurface destVolume = NULL;
4910 for (i = 0 ; i < levels ; ++i) {
4911 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4912 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4913 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4914 IWineD3DVolume_Release(srcSurface);
4915 IWineD3DVolume_Release(destSurface);
4916 if (WINED3D_OK != hr) {
4917 WARN("(%p) : Call to update volume failed\n", This);
4925 FIXME("(%p) : Unsupported source and destination type\n", This);
4926 hr = WINED3DERR_INVALIDCALL;
4933 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
4934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4935 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
4936 * NOTE It may be best to move the code into surface to occomplish this
4937 ****************************************/
4939 WINED3DSURFACE_DESC surfaceDesc;
4940 unsigned int surfaceWidth, surfaceHeight;
4941 glDescriptor *targetGlDescription = NULL;
4942 glDescriptor *surfaceGlDescription = NULL;
4943 IWineD3DSwapChainImpl *container = NULL;
4945 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
4946 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
4947 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
4949 surfaceDesc.Width = &surfaceWidth;
4950 surfaceDesc.Height = &surfaceHeight;
4951 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
4952 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
4954 /* Ok, I may need to setup some kind of active swapchain reference on the device */
4955 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
4957 /* TODO: opengl Context switching for swapchains etc... */
4958 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
4959 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
4960 glReadBuffer(GL_BACK);
4961 vcheckGLcall("glReadBuffer(GL_BACK)");
4962 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
4963 glReadBuffer(GL_FRONT);
4964 vcheckGLcall("glReadBuffer(GL_FRONT)");
4965 } else if (pRenderTarget == This->depthStencilBuffer) {
4966 FIXME("Reading of depthstencil not yet supported\n");
4973 surfaceGlDescription->glFormat,
4974 surfaceGlDescription->glType,
4975 (void *)IWineD3DSurface_GetData(pSurface));
4976 vcheckGLcall("glReadPixels(...)");
4977 if(NULL != container ){
4978 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
4981 IWineD3DBaseTexture *container;
4982 GLenum textureDimensions = GL_TEXTURE_2D;
4984 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
4985 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
4986 IWineD3DBaseTexture_Release(container);
4988 /* TODO: 2D -> Cube surface coppies etc.. */
4989 if (surfaceGlDescription->target != textureDimensions) {
4990 FIXME("(%p) : Texture dimension mismatch\n", This);
4992 glEnable(textureDimensions);
4993 vcheckGLcall("glEnable(GL_TEXTURE_...)");
4994 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
4995 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
4996 vcheckGLcall("glBindTexture");
4997 glGetTexImage(surfaceGlDescription->target,
4998 surfaceGlDescription->level,
4999 surfaceGlDescription->glFormat,
5000 surfaceGlDescription->glType,
5001 (void *)IWineD3DSurface_GetData(pSurface));
5002 glDisable(textureDimensions);
5003 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5010 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5011 IWineD3DSwapChain *swapChain;
5013 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5014 if(hr == WINED3D_OK) {
5015 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5016 IWineD3DSwapChain_Release(swapChain);
5021 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5023 /* return a sensible default */
5025 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5026 FIXME("(%p) : stub\n", This);
5030 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5033 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5034 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5035 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5036 return WINED3DERR_INVALIDCALL;
5038 for (j = 0; j < 256; ++j) {
5039 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5040 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5041 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5042 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5044 TRACE("(%p) : returning\n", This);
5048 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5051 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5052 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5053 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5054 return WINED3DERR_INVALIDCALL;
5056 for (j = 0; j < 256; ++j) {
5057 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5058 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5059 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5060 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5062 TRACE("(%p) : returning\n", This);
5066 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5068 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5069 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5070 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5071 return WINED3DERR_INVALIDCALL;
5073 /*TODO: stateblocks */
5074 This->currentPalette = PaletteNumber;
5075 TRACE("(%p) : returning\n", This);
5079 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5081 if (PaletteNumber == NULL) {
5082 WARN("(%p) : returning Invalid Call\n", This);
5083 return WINED3DERR_INVALIDCALL;
5085 /*TODO: stateblocks */
5086 *PaletteNumber = This->currentPalette;
5087 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5091 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5093 static BOOL showFixmes = TRUE;
5095 FIXME("(%p) : stub\n", This);
5099 This->softwareVertexProcessing = bSoftware;
5104 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 static BOOL showFixmes = TRUE;
5108 FIXME("(%p) : stub\n", This);
5111 return This->softwareVertexProcessing;
5115 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5117 IWineD3DSwapChain *swapChain;
5120 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5122 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5123 if(hr == WINED3D_OK){
5124 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5125 IWineD3DSwapChain_Release(swapChain);
5127 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5133 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 static BOOL showfixmes = TRUE;
5136 if(nSegments != 0.0f) {
5138 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5145 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5147 static BOOL showfixmes = TRUE;
5149 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5155 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5157 /** TODO: remove casts to IWineD3DSurfaceImpl
5158 * NOTE: move code to surface to accomplish this
5159 ****************************************/
5160 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5161 int srcWidth, srcHeight;
5162 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5163 WINED3DFORMAT destFormat, srcFormat;
5165 int srcLeft, destLeft, destTop;
5166 WINED3DPOOL srcPool, destPool;
5168 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5169 glDescriptor *glDescription = NULL;
5170 GLenum textureDimensions = GL_TEXTURE_2D;
5171 IWineD3DBaseTexture *baseTexture;
5173 WINED3DSURFACE_DESC winedesc;
5175 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5176 memset(&winedesc, 0, sizeof(winedesc));
5177 winedesc.Width = &srcSurfaceWidth;
5178 winedesc.Height = &srcSurfaceHeight;
5179 winedesc.Pool = &srcPool;
5180 winedesc.Format = &srcFormat;
5182 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5184 winedesc.Width = &destSurfaceWidth;
5185 winedesc.Height = &destSurfaceHeight;
5186 winedesc.Pool = &destPool;
5187 winedesc.Format = &destFormat;
5188 winedesc.Size = &destSize;
5190 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5192 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5193 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5194 return WINED3DERR_INVALIDCALL;
5197 if (destFormat == WINED3DFMT_UNKNOWN) {
5198 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5199 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5201 /* Get the update surface description */
5202 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5205 /* Make sure the surface is loaded and up to date */
5206 IWineD3DSurface_PreLoad(pDestinationSurface);
5208 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5212 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5213 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5214 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5215 srcLeft = pSourceRect ? pSourceRect->left : 0;
5216 destLeft = pDestPoint ? pDestPoint->x : 0;
5217 destTop = pDestPoint ? pDestPoint->y : 0;
5220 /* This function doesn't support compressed textures
5221 the pitch is just bytesPerPixel * width */
5222 if(srcWidth != srcSurfaceWidth || srcLeft ){
5223 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5224 offset += srcLeft * pSrcSurface->bytesPerPixel;
5225 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5227 /* TODO DXT formats */
5229 if(pSourceRect != NULL && pSourceRect->top != 0){
5230 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5232 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5234 ,glDescription->level
5239 ,glDescription->glFormat
5240 ,glDescription->glType
5241 ,IWineD3DSurface_GetData(pSourceSurface)
5245 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5247 /* need to lock the surface to get the data */
5248 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5251 /* TODO: Cube and volume support */
5253 /* not a whole row so we have to do it a line at a time */
5256 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5257 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5259 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5261 glTexSubImage2D(glDescription->target
5262 ,glDescription->level
5267 ,glDescription->glFormat
5268 ,glDescription->glType
5269 ,data /* could be quicker using */
5274 } else { /* Full width, so just write out the whole texture */
5276 if (WINED3DFMT_DXT1 == destFormat ||
5277 WINED3DFMT_DXT2 == destFormat ||
5278 WINED3DFMT_DXT3 == destFormat ||
5279 WINED3DFMT_DXT4 == destFormat ||
5280 WINED3DFMT_DXT5 == destFormat) {
5281 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5282 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5283 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5284 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5285 } if (destFormat != srcFormat) {
5286 FIXME("Updating mixed format compressed texture is not curretly support\n");
5288 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5289 glDescription->level,
5290 glDescription->glFormatInternal,
5295 IWineD3DSurface_GetData(pSourceSurface));
5298 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5303 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5305 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5306 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5307 data returned by GetData non-power2 width/height with hardware non-power2
5308 pow2Width/height are set to surface width height, repacking isn't needed so it
5309 doesn't matter which function gets called. */
5310 glTexSubImage2D(glDescription->target
5311 ,glDescription->level
5316 ,glDescription->glFormat
5317 ,glDescription->glType
5318 ,IWineD3DSurface_GetData(pSourceSurface)
5322 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5323 glTexSubImage2D(glDescription->target
5324 ,glDescription->level
5327 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5328 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5329 ,glDescription->glFormat
5330 ,glDescription->glType
5331 ,IWineD3DSurface_GetData(pSourceSurface)
5337 checkGLcall("glTexSubImage2D");
5338 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5340 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5341 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5342 * surface bigger than it needs to be hmm.. */
5343 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5344 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5345 IWineD3DBaseTexture_Release(baseTexture);
5348 glDisable(textureDimensions); /* This needs to be managed better.... */
5354 /* Implementation details at http://developer.nvidia.com/attach/6494
5356 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5357 hmm.. no longer supported use
5358 OpenGL evaluators or tessellate surfaces within your application.
5361 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5362 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5365 FIXME("(%p) : Stub\n", This);
5370 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5371 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5373 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5374 FIXME("(%p) : Stub\n", This);
5378 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5380 TRACE("(%p) Handle(%d)\n", This, Handle);
5381 FIXME("(%p) : Stub\n", This);
5385 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5387 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5389 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5391 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5392 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5393 return WINED3DERR_INVALIDCALL;
5396 /* Just forward this to the DirectDraw blitting engine */
5397 memset(&BltFx, 0, sizeof(BltFx));
5398 BltFx.dwSize = sizeof(BltFx);
5399 BltFx.u5.dwFillColor = color;
5400 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5403 /* rendertarget and deptth stencil functions */
5404 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5407 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5408 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5409 return WINED3DERR_INVALIDCALL;
5412 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5413 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5414 /* Note inc ref on returned surface */
5415 if(*ppRenderTarget != NULL)
5416 IWineD3DSurface_AddRef(*ppRenderTarget);
5420 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5422 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5423 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5424 IWineD3DSwapChainImpl *Swapchain;
5427 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5429 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5430 if(hr != WINED3D_OK) {
5431 ERR("Can't get the swapchain\n");
5435 /* Make sure to release the swapchain */
5436 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5438 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5439 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5440 return WINED3DERR_INVALIDCALL;
5442 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5443 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5444 return WINED3DERR_INVALIDCALL;
5447 if(Swapchain->frontBuffer != Front) {
5448 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5450 if(Swapchain->frontBuffer)
5451 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5452 Swapchain->frontBuffer = Front;
5454 if(Swapchain->frontBuffer) {
5455 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5459 if(Back && !Swapchain->backBuffer) {
5460 /* We need memory for the back buffer array - only one back buffer this way */
5461 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5462 if(!Swapchain->backBuffer) {
5463 ERR("Out of memory\n");
5464 return E_OUTOFMEMORY;
5468 if(Swapchain->backBuffer[0] != Back) {
5469 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5471 if(!Swapchain->backBuffer[0]) {
5472 /* GL was told to draw to the front buffer at creation,
5475 glDrawBuffer(GL_BACK);
5476 checkGLcall("glDrawBuffer(GL_BACK)");
5477 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5478 Swapchain->presentParms.BackBufferCount = 1;
5480 /* That makes problems - disable for now */
5481 /* glDrawBuffer(GL_FRONT); */
5482 checkGLcall("glDrawBuffer(GL_FRONT)");
5483 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5484 Swapchain->presentParms.BackBufferCount = 0;
5488 if(Swapchain->backBuffer[0])
5489 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5490 Swapchain->backBuffer[0] = Back;
5492 if(Swapchain->backBuffer[0]) {
5493 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5495 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5503 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5505 *ppZStencilSurface = This->depthStencilBuffer;
5506 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5508 if(*ppZStencilSurface != NULL) {
5509 /* Note inc ref on returned surface */
5510 IWineD3DSurface_AddRef(*ppZStencilSurface);
5515 static void bind_fbo(IWineD3DDevice *iface) {
5516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5519 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5520 checkGLcall("glGenFramebuffersEXT()");
5522 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5523 checkGLcall("glBindFramebuffer()");
5526 /* TODO: Handle stencil attachments */
5527 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5529 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5531 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5535 if (depth_stencil_impl) {
5536 GLenum texttarget, target;
5537 GLint old_binding = 0;
5539 IWineD3DSurface_PreLoad(depth_stencil);
5540 texttarget = depth_stencil_impl->glDescription.target;
5541 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5543 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5544 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5545 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5546 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5547 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5548 glBindTexture(target, old_binding);
5550 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5551 checkGLcall("glFramebufferTexture2DEXT()");
5553 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5554 checkGLcall("glFramebufferTexture2DEXT()");
5557 if (!This->render_offscreen) {
5558 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5559 checkGLcall("glBindFramebuffer()");
5563 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5565 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5567 if (idx >= GL_LIMITS(buffers)) {
5568 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5574 GLenum texttarget, target;
5575 GLint old_binding = 0;
5577 IWineD3DSurface_PreLoad(render_target);
5578 texttarget = rtimpl->glDescription.target;
5579 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5581 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5582 glBindTexture(target, rtimpl->glDescription.textureName);
5583 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5584 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5585 glBindTexture(target, old_binding);
5587 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5588 checkGLcall("glFramebufferTexture2DEXT()");
5590 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5592 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5593 checkGLcall("glFramebufferTexture2DEXT()");
5595 This->draw_buffers[idx] = GL_NONE;
5598 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5599 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5600 checkGLcall("glDrawBuffers()");
5603 if (!This->render_offscreen) {
5604 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5605 checkGLcall("glBindFramebuffer()");
5609 /* internal static helper functions */
5610 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5611 IWineD3DSurface *RenderSurface);
5613 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5615 HRESULT hr = WINED3D_OK;
5616 WINED3DVIEWPORT viewport;
5618 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5620 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5621 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5622 return WINED3DERR_INVALIDCALL;
5625 /* MSDN says that null disables the render target
5626 but a device must always be associated with a render target
5627 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5629 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5632 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5633 FIXME("Trying to set render target 0 to NULL\n");
5634 return WINED3DERR_INVALIDCALL;
5636 /* TODO: replace Impl* usage with interface usage */
5637 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5638 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);
5639 return WINED3DERR_INVALIDCALL;
5641 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5642 * builds, but I think wine counts as a 'debug' build for now.
5643 ******************************/
5644 /* If we are trying to set what we already have, don't bother */
5645 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5646 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5648 /* Otherwise, set the render target up */
5650 if (!This->sceneEnded) {
5651 IWineD3DDevice_EndScene(iface);
5653 TRACE("clearing renderer\n");
5654 /* IWineD3DDeviceImpl_CleanRender(iface); */
5655 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5656 depending on the renter target implementation being used.
5657 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5658 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5659 stencil buffer and incure an extra memory overhead */
5660 if (RenderTargetIndex == 0) {
5661 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5666 /* Replace the render target */
5667 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5668 This->render_targets[RenderTargetIndex] = pRenderTarget;
5669 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5671 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5672 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5676 if (SUCCEEDED(hr)) {
5677 /* Finally, reset the viewport as the MSDN states. */
5678 /* TODO: Replace impl usage */
5679 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5680 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5683 viewport.MaxZ = 1.0f;
5684 viewport.MinZ = 0.0f;
5685 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5687 FIXME("Unknown error setting the render target\n");
5689 This->sceneEnded = FALSE;
5693 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5695 HRESULT hr = WINED3D_OK;
5696 IWineD3DSurface *tmp;
5698 TRACE("(%p) Swapping z-buffer\n",This);
5700 if (pNewZStencil == This->stencilBufferTarget) {
5701 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5703 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5704 * depending on the renter target implementation being used.
5705 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5706 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5707 * stencil buffer and incure an extra memory overhead
5708 ******************************************************/
5711 tmp = This->stencilBufferTarget;
5712 This->stencilBufferTarget = pNewZStencil;
5713 /* should we be calling the parent or the wined3d surface? */
5714 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5715 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5717 /** TODO: glEnable/glDisable on depth/stencil depending on
5718 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5719 **********************************************************/
5720 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5721 set_depth_stencil_fbo(iface, pNewZStencil);
5729 #ifdef GL_VERSION_1_3
5730 /* Internal functions not in DirectX */
5731 /** TODO: move this off to the opengl context manager
5732 *(the swapchain doesn't need to know anything about offscreen rendering!)
5733 ****************************************************/
5735 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 TRACE("(%p), %p\n", This, swapchain);
5741 if (swapchain->win != swapchain->drawable) {
5742 /* Set everything back the way it ws */
5743 swapchain->render_ctx = swapchain->glCtx;
5744 swapchain->drawable = swapchain->win;
5749 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5750 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5754 unsigned int height;
5755 WINED3DFORMAT format;
5756 WINED3DSURFACE_DESC surfaceDesc;
5757 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5758 surfaceDesc.Width = &width;
5759 surfaceDesc.Height = &height;
5760 surfaceDesc.Format = &format;
5761 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5763 /* I need a get width/height function (and should do something with the format) */
5764 for (i = 0; i < CONTEXT_CACHE; ++i) {
5765 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5766 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5767 the pSurface can be set to 0 allowing it to be reused from cache **/
5768 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5769 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5770 *context = &This->contextCache[i];
5773 if (This->contextCache[i].Width == 0) {
5774 This->contextCache[i].pSurface = pSurface;
5775 This->contextCache[i].Width = width;
5776 This->contextCache[i].Height = height;
5777 *context = &This->contextCache[i];
5781 if (i == CONTEXT_CACHE) {
5782 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5783 glContext *dropContext = 0;
5784 for (i = 0; i < CONTEXT_CACHE; i++) {
5785 if (This->contextCache[i].usedcount < minUsage) {
5786 dropContext = &This->contextCache[i];
5787 minUsage = This->contextCache[i].usedcount;
5790 /* clean up the context (this doesn't work for ATI at the moment */
5792 glXDestroyContext(swapchain->display, dropContext->context);
5793 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5796 dropContext->Width = 0;
5797 dropContext->pSurface = pSurface;
5798 *context = dropContext;
5800 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5801 for (i = 0; i < CONTEXT_CACHE; i++) {
5802 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
5806 if (*context != NULL)
5809 return E_OUTOFMEMORY;
5813 /* Reapply the device stateblock */
5814 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
5817 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5820 /* Disable recording */
5821 oldUpdateStateBlock = This->updateStateBlock;
5822 oldRecording= This->isRecordingState;
5823 This->isRecordingState = FALSE;
5824 This->updateStateBlock = This->stateBlock;
5826 /* Reapply the state block */
5827 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
5829 /* Temporaryily mark all render states dirty to force reapplication
5830 * until the context management for is integrated with the state management
5831 * The same for the pixel shader, vertex declaration and vertex shader
5832 * Sampler states and texture stage states are marked
5833 * dirty my StateBlock::Apply already.
5835 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
5836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
5838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5839 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
5842 /* Restore recording */
5843 This->isRecordingState = oldRecording;
5844 This->updateStateBlock = oldUpdateStateBlock;
5847 /* Set offscreen rendering. When rendering offscreen the surface will be
5848 * rendered upside down to compensate for the fact that D3D texture coordinates
5849 * are flipped compared to GL texture coordinates. The cullmode is affected by
5850 * this, so it must be updated. To update the cullmode stateblock recording has
5851 * to be temporarily disabled. The new state management code will hopefully
5852 * make this unnecessary */
5853 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
5856 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5858 /* Nothing to update, return. */
5859 if (This->render_offscreen == isTexture) return;
5861 /* Disable recording */
5862 oldUpdateStateBlock = This->updateStateBlock;
5863 oldRecording= This->isRecordingState;
5864 This->isRecordingState = FALSE;
5865 This->updateStateBlock = This->stateBlock;
5867 This->render_offscreen = isTexture;
5868 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
5869 This->depth_copy_state = WINED3D_DCS_COPY;
5871 This->last_was_rhw = FALSE;
5872 /* Viewport state will reapply the projection matrix for now */
5873 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
5875 /* Restore recording */
5876 This->isRecordingState = oldRecording;
5877 This->updateStateBlock = oldUpdateStateBlock;
5880 /* Returns an array of compatible FBconfig(s).
5881 * The array must be freed with XFree. Requires ENTER_GL() */
5883 static GLXFBConfig* device_find_fbconfigs(
5884 IWineD3DDeviceImpl* This,
5885 IWineD3DSwapChainImpl* implicitSwapchainImpl,
5886 IWineD3DSurface* RenderSurface) {
5888 GLXFBConfig* cfgs = NULL;
5893 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
5894 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
5895 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
5898 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5899 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5902 #define PUSH1(att) attribs[nAttribs++] = (att);
5903 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5905 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
5907 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
5908 PUSH2(GLX_X_RENDERABLE, TRUE);
5909 PUSH2(GLX_DOUBLEBUFFER, TRUE);
5910 TRACE("calling makeglcfg\n");
5911 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
5913 TRACE("calling chooseFGConfig\n");
5914 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5915 DefaultScreen(implicitSwapchainImpl->display),
5918 /* OK we didn't find the exact config, so use any reasonable match */
5919 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
5921 static BOOL show_message = TRUE;
5923 ERR("Failed to find exact match, finding alternative but you may "
5924 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
5925 show_message = FALSE;
5928 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
5929 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
5930 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
5931 PUSH2(GLX_DOUBLEBUFFER, FALSE);
5932 TRACE("calling makeglcfg\n");
5933 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
5935 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5936 DefaultScreen(implicitSwapchainImpl->display),
5941 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
5942 BackBufferFormat, debug_d3dformat(BackBufferFormat),
5943 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
5947 for (i = 0; i < nCfgs; ++i) {
5948 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
5949 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
5950 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
5952 if (NULL != This->renderTarget) {
5954 vcheckGLcall("glFlush");
5955 /** This is only useful if the old render target was a swapchain,
5956 * we need to supercede this with a function that displays
5957 * the current buffer on the screen. This is easy to do in glx1.3 but
5958 * we need to do copy-write pixels in glx 1.2.
5959 ************************************************/
5960 glXSwapBuffers(implicitSwapChainImpl->display,
5961 implicitSwapChainImpl->drawable);
5962 printf("Hit Enter to get next frame ...\n");
5973 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
5974 * the functionality needs splitting up so that we don't do more than we should do.
5975 * this only seems to impact performance a little.
5976 ******************************/
5977 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5978 IWineD3DSurface *RenderSurface) {
5981 * Currently only active for GLX >= 1.3
5982 * for others versions we'll have to use GLXPixmaps
5984 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
5985 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
5986 * so only check OpenGL version
5987 * ..........................
5988 * I don't believe that it is a problem with NVidia headers,
5989 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
5990 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
5992 * Your application will report GLX version 1.2 on glXQueryVersion.
5993 * However, it is safe to call the GLX 1.3 functions as described below.
5995 #if defined(GL_VERSION_1_3)
5997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5998 GLXFBConfig* cfgs = NULL;
5999 IWineD3DSwapChain *currentSwapchain;
6000 IWineD3DSwapChainImpl *currentSwapchainImpl;
6001 IWineD3DSwapChain *implicitSwapchain;
6002 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6003 IWineD3DSwapChain *renderSurfaceSwapchain;
6004 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6006 /* Obtain a reference to the device implicit swapchain,
6007 * the swapchain of the current render target,
6008 * and the swapchain of the new render target.
6009 * Fallback to device implicit swapchain if the current render target doesn't have one */
6010 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6011 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6012 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)¤tSwapchain);
6013 if (currentSwapchain == NULL)
6014 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
6016 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6017 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6018 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6023 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6024 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6025 **********************************************************************/
6026 if (renderSurfaceSwapchain != NULL) {
6028 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6029 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6030 TRACE("making swapchain active\n");
6031 if (RenderSurface != This->render_targets[0]) {
6032 BOOL backbuf = FALSE;
6035 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6036 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6044 /* This could be flagged so that some operations work directly with the front buffer */
6045 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6047 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6048 renderSurfaceSwapchainImpl->win,
6049 renderSurfaceSwapchainImpl->glCtx) == False) {
6051 TRACE("Error in setting current context: context %p drawable %ld !\n",
6052 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6054 checkGLcall("glXMakeContextCurrent");
6056 /* Clean up the old context */
6057 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6059 /* Reapply the stateblock, and set the device not to render to texture */
6060 device_reapply_stateblock(This);
6061 device_render_to_texture(This, FALSE);
6064 /* Offscreen rendering: PBuffers (currently disabled).
6065 * Also note that this path is never reached if FBOs are supported */
6066 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6067 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6069 /** ********************************************************************
6070 * This is a quickly hacked out implementation of offscreen textures.
6071 * It will work in most cases but there may be problems if the client
6072 * modifies the texture directly, or expects the contents of the rendertarget
6075 * There are some real speed vs compatibility issues here:
6076 * we should really use a new context for every texture, but that eats ram.
6077 * we should also be restoring the texture to the pbuffer but that eats CPU
6078 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6079 * but if this means reusing the display backbuffer then we need to make sure that
6080 * states are correctly preserved.
6081 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6082 * and gain a good performance increase at the cost of compatibility.
6083 * I would suggest that, when this is the case, a user configurable flag be made
6084 * available, allowing the user to choose the best emulated experience for them.
6085 *********************************************************************/
6087 XVisualInfo *visinfo;
6088 glContext *newContext;
6090 /* Here were using a shared context model */
6091 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6092 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6095 /* If the context doesn't exist then create a new one */
6096 /* TODO: This should really be part of findGlContext */
6097 if (NULL == newContext->context) {
6102 TRACE("making new buffer\n");
6103 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6104 attribs[nAttribs++] = newContext->Width;
6105 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6106 attribs[nAttribs++] = newContext->Height;
6107 attribs[nAttribs++] = None;
6109 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6111 /** ****************************************
6112 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6114 * In future releases, we may provide the calls glXCreateNewContext,
6115 * glXQueryDrawable and glXMakeContextCurrent.
6116 * so until then we have to use glXGetVisualFromFBConfig &co..
6117 ********************************************/
6119 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6121 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6123 newContext->context = glXCreateContext(
6124 implicitSwapchainImpl->display, visinfo,
6125 implicitSwapchainImpl->glCtx, GL_TRUE);
6130 if (NULL == newContext || NULL == newContext->context) {
6131 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6133 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6134 if (glXMakeCurrent(implicitSwapchainImpl->display,
6135 newContext->drawable, newContext->context) == False) {
6137 TRACE("Error in setting current context: context %p drawable %ld\n",
6138 newContext->context, newContext->drawable);
6140 checkGLcall("glXMakeContextCurrent");
6142 /* Clean up the old context */
6143 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6145 /* Reapply stateblock, and set device to render to a texture */
6146 device_reapply_stateblock(This);
6147 device_render_to_texture(This, TRUE);
6149 /* Set the current context of the swapchain to the new context */
6150 implicitSwapchainImpl->drawable = newContext->drawable;
6151 implicitSwapchainImpl->render_ctx = newContext->context;
6154 /* Same context, but update render_offscreen and cull mode */
6155 device_render_to_texture(This, TRUE);
6158 if (cfgs != NULL) XFree(cfgs);
6159 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6160 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6161 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6167 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6168 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6170 /* TODO: the use of Impl is deprecated. */
6171 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6173 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6175 /* some basic validation checks */
6176 if(This->cursorTexture) {
6178 glDeleteTextures(1, &This->cursorTexture);
6180 This->cursorTexture = 0;
6184 /* MSDN: Cursor must be A8R8G8B8 */
6185 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6186 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6187 return WINED3DERR_INVALIDCALL;
6190 /* MSDN: Cursor must be smaller than the display mode */
6191 if(pSur->currentDesc.Width > This->ddraw_width ||
6192 pSur->currentDesc.Height > This->ddraw_height) {
6193 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);
6194 return WINED3DERR_INVALIDCALL;
6197 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6198 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6199 * Texture and Blitting code to draw the cursor
6201 pSur->Flags |= SFLAG_FORCELOAD;
6202 IWineD3DSurface_PreLoad(pCursorBitmap);
6203 pSur->Flags &= ~SFLAG_FORCELOAD;
6204 /* Do not store the surface's pointer because the application may release
6205 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6206 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6208 This->cursorTexture = pSur->glDescription.textureName;
6209 This->cursorWidth = pSur->currentDesc.Width;
6210 This->cursorHeight = pSur->currentDesc.Height;
6211 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6214 This->xHotSpot = XHotSpot;
6215 This->yHotSpot = YHotSpot;
6219 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6221 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6223 This->xScreenSpace = XScreenSpace;
6224 This->yScreenSpace = YScreenSpace;
6230 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6232 BOOL oldVisible = This->bCursorVisible;
6233 TRACE("(%p) : visible(%d)\n", This, bShow);
6235 if(This->cursorTexture)
6236 This->bCursorVisible = bShow;
6241 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6243 TRACE("(%p) : state (%u)\n", This, This->state);
6244 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6245 switch (This->state) {
6248 case WINED3DERR_DEVICELOST:
6250 ResourceList *resourceList = This->resources;
6251 while (NULL != resourceList) {
6252 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6253 return WINED3DERR_DEVICENOTRESET;
6254 resourceList = resourceList->next;
6256 return WINED3DERR_DEVICELOST;
6258 case WINED3DERR_DRIVERINTERNALERROR:
6259 return WINED3DERR_DRIVERINTERNALERROR;
6263 return WINED3DERR_DRIVERINTERNALERROR;
6267 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6269 /** FIXME: Resource tracking needs to be done,
6270 * The closes we can do to this is set the priorities of all managed textures low
6271 * and then reset them.
6272 ***********************************************************/
6273 FIXME("(%p) : stub\n", This);
6277 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6278 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6279 if(surface->Flags & SFLAG_DIBSECTION) {
6280 /* Release the DC */
6281 SelectObject(surface->hDC, surface->dib.holdbitmap);
6282 DeleteDC(surface->hDC);
6283 /* Release the DIB section */
6284 DeleteObject(surface->dib.DIBsection);
6285 surface->dib.bitmap_data = NULL;
6286 surface->resource.allocatedMemory = NULL;
6287 surface->Flags &= ~SFLAG_DIBSECTION;
6289 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6290 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6291 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6292 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6293 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6295 surface->pow2Width = surface->pow2Height = 1;
6296 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6297 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6299 if(surface->glDescription.textureName) {
6301 glDeleteTextures(1, &surface->glDescription.textureName);
6303 surface->glDescription.textureName = 0;
6305 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6306 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6307 surface->Flags |= SFLAG_NONPOW2;
6309 surface->Flags &= ~SFLAG_NONPOW2;
6311 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6312 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6315 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6317 IWineD3DSwapChainImpl *swapchain;
6319 BOOL DisplayModeChanged = FALSE;
6320 WINED3DDISPLAYMODE mode;
6321 TRACE("(%p)\n", This);
6323 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6325 ERR("Failed to get the first implicit swapchain\n");
6329 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6330 * on an existing gl context, so there's no real need for recreation.
6332 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6334 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6336 TRACE("New params:\n");
6337 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6338 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6339 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6340 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6341 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6342 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6343 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6344 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6345 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6346 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6347 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6348 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6349 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6351 /* No special treatment of these parameters. Just store them */
6352 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6353 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6354 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6355 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6357 /* What to do about these? */
6358 if(*pPresentationParameters->BackBufferCount != 0 &&
6359 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6360 ERR("Cannot change the back buffer count yet\n");
6362 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6363 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6364 ERR("Cannot change the back buffer format yet\n");
6366 if(*pPresentationParameters->hDeviceWindow != NULL &&
6367 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6368 ERR("Cannot change the device window yet\n");
6370 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6371 ERR("What do do about a changed auto depth stencil parameter?\n");
6374 if(*pPresentationParameters->Windowed) {
6375 mode.Width = swapchain->orig_width;
6376 mode.Height = swapchain->orig_height;
6377 mode.RefreshRate = 0;
6378 mode.Format = swapchain->presentParms.BackBufferFormat;
6380 mode.Width = *pPresentationParameters->BackBufferWidth;
6381 mode.Height = *pPresentationParameters->BackBufferHeight;
6382 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6383 mode.Format = swapchain->presentParms.BackBufferFormat;
6386 /* Should Width == 800 && Height == 0 set 800x600? */
6387 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6388 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6389 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6396 vp.Width = *pPresentationParameters->BackBufferWidth;
6397 vp.Height = *pPresentationParameters->BackBufferHeight;
6401 if(!*pPresentationParameters->Windowed) {
6402 DisplayModeChanged = TRUE;
6404 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6405 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6407 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6408 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6409 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6412 /* Now set the new viewport */
6413 IWineD3DDevice_SetViewport(iface, &vp);
6416 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6417 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6418 DisplayModeChanged) {
6419 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6422 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6426 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6428 /** FIXME: always true at the moment **/
6429 if(!bEnableDialogs) {
6430 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6436 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6438 TRACE("(%p) : pParameters %p\n", This, pParameters);
6440 *pParameters = This->createParms;
6444 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6445 IWineD3DSwapChain *swapchain;
6446 HRESULT hrc = WINED3D_OK;
6448 TRACE("Relaying to swapchain\n");
6450 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6451 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6452 IWineD3DSwapChain_Release(swapchain);
6457 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6458 IWineD3DSwapChain *swapchain;
6459 HRESULT hrc = WINED3D_OK;
6461 TRACE("Relaying to swapchain\n");
6463 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6464 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6465 IWineD3DSwapChain_Release(swapchain);
6471 /** ********************************************************
6472 * Notification functions
6473 ** ********************************************************/
6474 /** This function must be called in the release of a resource when ref == 0,
6475 * the contents of resource must still be correct,
6476 * any handels to other resource held by the caller must be closed
6477 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6478 *****************************************************/
6479 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6481 ResourceList* resourceList;
6483 TRACE("(%p) : resource %p\n", This, resource);
6485 EnterCriticalSection(&resourceStoreCriticalSection);
6487 /* add a new texture to the frot of the linked list */
6488 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6489 resourceList->resource = resource;
6491 /* Get the old head */
6492 resourceList->next = This->resources;
6494 This->resources = resourceList;
6495 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6498 LeaveCriticalSection(&resourceStoreCriticalSection);
6503 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6505 ResourceList* resourceList = NULL;
6506 ResourceList* previousResourceList = NULL;
6508 TRACE("(%p) : resource %p\n", This, resource);
6511 EnterCriticalSection(&resourceStoreCriticalSection);
6513 resourceList = This->resources;
6515 while (resourceList != NULL) {
6516 if(resourceList->resource == resource) break;
6517 previousResourceList = resourceList;
6518 resourceList = resourceList->next;
6521 if (resourceList == NULL) {
6522 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6524 LeaveCriticalSection(&resourceStoreCriticalSection);
6528 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6530 /* make sure we don't leave a hole in the list */
6531 if (previousResourceList != NULL) {
6532 previousResourceList->next = resourceList->next;
6534 This->resources = resourceList->next;
6538 LeaveCriticalSection(&resourceStoreCriticalSection);
6544 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6548 TRACE("(%p) : resource %p\n", This, resource);
6549 switch(IWineD3DResource_GetType(resource)){
6550 case WINED3DRTYPE_SURFACE:
6551 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6553 case WINED3DRTYPE_TEXTURE:
6554 case WINED3DRTYPE_CUBETEXTURE:
6555 case WINED3DRTYPE_VOLUMETEXTURE:
6556 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6557 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6558 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6559 This->stateBlock->textures[counter] = NULL;
6561 if (This->updateStateBlock != This->stateBlock ){
6562 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6563 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6564 This->updateStateBlock->textures[counter] = NULL;
6569 case WINED3DRTYPE_VOLUME:
6570 /* TODO: nothing really? */
6572 case WINED3DRTYPE_VERTEXBUFFER:
6573 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6576 TRACE("Cleaning up stream pointers\n");
6578 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6579 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6580 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6582 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6583 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6584 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6585 This->updateStateBlock->streamSource[streamNumber] = 0;
6586 /* Set changed flag? */
6589 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) */
6590 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6591 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6592 This->stateBlock->streamSource[streamNumber] = 0;
6595 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6596 else { /* This shouldn't happen */
6597 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6604 case WINED3DRTYPE_INDEXBUFFER:
6605 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6606 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6607 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6608 This->updateStateBlock->pIndexData = NULL;
6611 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6612 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6613 This->stateBlock->pIndexData = NULL;
6619 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6624 /* Remove the resoruce from the resourceStore */
6625 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6627 TRACE("Resource released\n");
6631 /**********************************************************
6632 * IWineD3DDevice VTbl follows
6633 **********************************************************/
6635 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6637 /*** IUnknown methods ***/
6638 IWineD3DDeviceImpl_QueryInterface,
6639 IWineD3DDeviceImpl_AddRef,
6640 IWineD3DDeviceImpl_Release,
6641 /*** IWineD3DDevice methods ***/
6642 IWineD3DDeviceImpl_GetParent,
6643 /*** Creation methods**/
6644 IWineD3DDeviceImpl_CreateVertexBuffer,
6645 IWineD3DDeviceImpl_CreateIndexBuffer,
6646 IWineD3DDeviceImpl_CreateStateBlock,
6647 IWineD3DDeviceImpl_CreateSurface,
6648 IWineD3DDeviceImpl_CreateTexture,
6649 IWineD3DDeviceImpl_CreateVolumeTexture,
6650 IWineD3DDeviceImpl_CreateVolume,
6651 IWineD3DDeviceImpl_CreateCubeTexture,
6652 IWineD3DDeviceImpl_CreateQuery,
6653 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6654 IWineD3DDeviceImpl_CreateVertexDeclaration,
6655 IWineD3DDeviceImpl_CreateVertexShader,
6656 IWineD3DDeviceImpl_CreatePixelShader,
6657 IWineD3DDeviceImpl_CreatePalette,
6658 /*** Odd functions **/
6659 IWineD3DDeviceImpl_Init3D,
6660 IWineD3DDeviceImpl_Uninit3D,
6661 IWineD3DDeviceImpl_SetFullscreen,
6662 IWineD3DDeviceImpl_EnumDisplayModes,
6663 IWineD3DDeviceImpl_EvictManagedResources,
6664 IWineD3DDeviceImpl_GetAvailableTextureMem,
6665 IWineD3DDeviceImpl_GetBackBuffer,
6666 IWineD3DDeviceImpl_GetCreationParameters,
6667 IWineD3DDeviceImpl_GetDeviceCaps,
6668 IWineD3DDeviceImpl_GetDirect3D,
6669 IWineD3DDeviceImpl_GetDisplayMode,
6670 IWineD3DDeviceImpl_SetDisplayMode,
6671 IWineD3DDeviceImpl_GetHWND,
6672 IWineD3DDeviceImpl_SetHWND,
6673 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6674 IWineD3DDeviceImpl_GetRasterStatus,
6675 IWineD3DDeviceImpl_GetSwapChain,
6676 IWineD3DDeviceImpl_Reset,
6677 IWineD3DDeviceImpl_SetDialogBoxMode,
6678 IWineD3DDeviceImpl_SetCursorProperties,
6679 IWineD3DDeviceImpl_SetCursorPosition,
6680 IWineD3DDeviceImpl_ShowCursor,
6681 IWineD3DDeviceImpl_TestCooperativeLevel,
6682 /*** Getters and setters **/
6683 IWineD3DDeviceImpl_SetClipPlane,
6684 IWineD3DDeviceImpl_GetClipPlane,
6685 IWineD3DDeviceImpl_SetClipStatus,
6686 IWineD3DDeviceImpl_GetClipStatus,
6687 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6688 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6689 IWineD3DDeviceImpl_SetDepthStencilSurface,
6690 IWineD3DDeviceImpl_GetDepthStencilSurface,
6691 IWineD3DDeviceImpl_SetFVF,
6692 IWineD3DDeviceImpl_GetFVF,
6693 IWineD3DDeviceImpl_SetGammaRamp,
6694 IWineD3DDeviceImpl_GetGammaRamp,
6695 IWineD3DDeviceImpl_SetIndices,
6696 IWineD3DDeviceImpl_GetIndices,
6697 IWineD3DDeviceImpl_SetBasevertexIndex,
6698 IWineD3DDeviceImpl_SetLight,
6699 IWineD3DDeviceImpl_GetLight,
6700 IWineD3DDeviceImpl_SetLightEnable,
6701 IWineD3DDeviceImpl_GetLightEnable,
6702 IWineD3DDeviceImpl_SetMaterial,
6703 IWineD3DDeviceImpl_GetMaterial,
6704 IWineD3DDeviceImpl_SetNPatchMode,
6705 IWineD3DDeviceImpl_GetNPatchMode,
6706 IWineD3DDeviceImpl_SetPaletteEntries,
6707 IWineD3DDeviceImpl_GetPaletteEntries,
6708 IWineD3DDeviceImpl_SetPixelShader,
6709 IWineD3DDeviceImpl_GetPixelShader,
6710 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6711 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6712 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6713 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6714 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6715 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6716 IWineD3DDeviceImpl_SetRenderState,
6717 IWineD3DDeviceImpl_GetRenderState,
6718 IWineD3DDeviceImpl_SetRenderTarget,
6719 IWineD3DDeviceImpl_GetRenderTarget,
6720 IWineD3DDeviceImpl_SetFrontBackBuffers,
6721 IWineD3DDeviceImpl_SetSamplerState,
6722 IWineD3DDeviceImpl_GetSamplerState,
6723 IWineD3DDeviceImpl_SetScissorRect,
6724 IWineD3DDeviceImpl_GetScissorRect,
6725 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6726 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6727 IWineD3DDeviceImpl_SetStreamSource,
6728 IWineD3DDeviceImpl_GetStreamSource,
6729 IWineD3DDeviceImpl_SetStreamSourceFreq,
6730 IWineD3DDeviceImpl_GetStreamSourceFreq,
6731 IWineD3DDeviceImpl_SetTexture,
6732 IWineD3DDeviceImpl_GetTexture,
6733 IWineD3DDeviceImpl_SetTextureStageState,
6734 IWineD3DDeviceImpl_GetTextureStageState,
6735 IWineD3DDeviceImpl_SetTransform,
6736 IWineD3DDeviceImpl_GetTransform,
6737 IWineD3DDeviceImpl_SetVertexDeclaration,
6738 IWineD3DDeviceImpl_GetVertexDeclaration,
6739 IWineD3DDeviceImpl_SetVertexShader,
6740 IWineD3DDeviceImpl_GetVertexShader,
6741 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6742 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6743 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6744 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6745 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6746 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6747 IWineD3DDeviceImpl_SetViewport,
6748 IWineD3DDeviceImpl_GetViewport,
6749 IWineD3DDeviceImpl_MultiplyTransform,
6750 IWineD3DDeviceImpl_ValidateDevice,
6751 IWineD3DDeviceImpl_ProcessVertices,
6752 /*** State block ***/
6753 IWineD3DDeviceImpl_BeginStateBlock,
6754 IWineD3DDeviceImpl_EndStateBlock,
6755 /*** Scene management ***/
6756 IWineD3DDeviceImpl_BeginScene,
6757 IWineD3DDeviceImpl_EndScene,
6758 IWineD3DDeviceImpl_Present,
6759 IWineD3DDeviceImpl_Clear,
6761 IWineD3DDeviceImpl_DrawPrimitive,
6762 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6763 IWineD3DDeviceImpl_DrawPrimitiveUP,
6764 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6765 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6766 IWineD3DDeviceImpl_DrawRectPatch,
6767 IWineD3DDeviceImpl_DrawTriPatch,
6768 IWineD3DDeviceImpl_DeletePatch,
6769 IWineD3DDeviceImpl_ColorFill,
6770 IWineD3DDeviceImpl_UpdateTexture,
6771 IWineD3DDeviceImpl_UpdateSurface,
6772 IWineD3DDeviceImpl_GetRenderTargetData,
6773 IWineD3DDeviceImpl_GetFrontBufferData,
6774 /*** object tracking ***/
6775 IWineD3DDeviceImpl_ResourceReleased
6779 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6780 WINED3DRS_ALPHABLENDENABLE ,
6781 WINED3DRS_ALPHAFUNC ,
6782 WINED3DRS_ALPHAREF ,
6783 WINED3DRS_ALPHATESTENABLE ,
6785 WINED3DRS_COLORWRITEENABLE ,
6786 WINED3DRS_DESTBLEND ,
6787 WINED3DRS_DITHERENABLE ,
6788 WINED3DRS_FILLMODE ,
6789 WINED3DRS_FOGDENSITY ,
6791 WINED3DRS_FOGSTART ,
6792 WINED3DRS_LASTPIXEL ,
6793 WINED3DRS_SHADEMODE ,
6794 WINED3DRS_SRCBLEND ,
6795 WINED3DRS_STENCILENABLE ,
6796 WINED3DRS_STENCILFAIL ,
6797 WINED3DRS_STENCILFUNC ,
6798 WINED3DRS_STENCILMASK ,
6799 WINED3DRS_STENCILPASS ,
6800 WINED3DRS_STENCILREF ,
6801 WINED3DRS_STENCILWRITEMASK ,
6802 WINED3DRS_STENCILZFAIL ,
6803 WINED3DRS_TEXTUREFACTOR ,
6814 WINED3DRS_ZWRITEENABLE
6817 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6818 WINED3DTSS_ADDRESSW ,
6819 WINED3DTSS_ALPHAARG0 ,
6820 WINED3DTSS_ALPHAARG1 ,
6821 WINED3DTSS_ALPHAARG2 ,
6822 WINED3DTSS_ALPHAOP ,
6823 WINED3DTSS_BUMPENVLOFFSET ,
6824 WINED3DTSS_BUMPENVLSCALE ,
6825 WINED3DTSS_BUMPENVMAT00 ,
6826 WINED3DTSS_BUMPENVMAT01 ,
6827 WINED3DTSS_BUMPENVMAT10 ,
6828 WINED3DTSS_BUMPENVMAT11 ,
6829 WINED3DTSS_COLORARG0 ,
6830 WINED3DTSS_COLORARG1 ,
6831 WINED3DTSS_COLORARG2 ,
6832 WINED3DTSS_COLOROP ,
6833 WINED3DTSS_RESULTARG ,
6834 WINED3DTSS_TEXCOORDINDEX ,
6835 WINED3DTSS_TEXTURETRANSFORMFLAGS
6838 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6839 WINED3DSAMP_ADDRESSU ,
6840 WINED3DSAMP_ADDRESSV ,
6841 WINED3DSAMP_ADDRESSW ,
6842 WINED3DSAMP_BORDERCOLOR ,
6843 WINED3DSAMP_MAGFILTER ,
6844 WINED3DSAMP_MINFILTER ,
6845 WINED3DSAMP_MIPFILTER ,
6846 WINED3DSAMP_MIPMAPLODBIAS ,
6847 WINED3DSAMP_MAXMIPLEVEL ,
6848 WINED3DSAMP_MAXANISOTROPY ,
6849 WINED3DSAMP_SRGBTEXTURE ,
6850 WINED3DSAMP_ELEMENTINDEX
6853 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6855 WINED3DRS_AMBIENTMATERIALSOURCE ,
6856 WINED3DRS_CLIPPING ,
6857 WINED3DRS_CLIPPLANEENABLE ,
6858 WINED3DRS_COLORVERTEX ,
6859 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6860 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6861 WINED3DRS_FOGDENSITY ,
6863 WINED3DRS_FOGSTART ,
6864 WINED3DRS_FOGTABLEMODE ,
6865 WINED3DRS_FOGVERTEXMODE ,
6866 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6867 WINED3DRS_LIGHTING ,
6868 WINED3DRS_LOCALVIEWER ,
6869 WINED3DRS_MULTISAMPLEANTIALIAS ,
6870 WINED3DRS_MULTISAMPLEMASK ,
6871 WINED3DRS_NORMALIZENORMALS ,
6872 WINED3DRS_PATCHEDGESTYLE ,
6873 WINED3DRS_POINTSCALE_A ,
6874 WINED3DRS_POINTSCALE_B ,
6875 WINED3DRS_POINTSCALE_C ,
6876 WINED3DRS_POINTSCALEENABLE ,
6877 WINED3DRS_POINTSIZE ,
6878 WINED3DRS_POINTSIZE_MAX ,
6879 WINED3DRS_POINTSIZE_MIN ,
6880 WINED3DRS_POINTSPRITEENABLE ,
6881 WINED3DRS_RANGEFOGENABLE ,
6882 WINED3DRS_SPECULARMATERIALSOURCE ,
6883 WINED3DRS_TWEENFACTOR ,
6884 WINED3DRS_VERTEXBLEND
6887 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6888 WINED3DTSS_TEXCOORDINDEX ,
6889 WINED3DTSS_TEXTURETRANSFORMFLAGS
6892 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6893 WINED3DSAMP_DMAPOFFSET
6896 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6897 DWORD rep = StateTable[state].representative;
6901 if(!rep || isStateDirty(This, rep)) return;
6903 This->dirtyArray[This->numDirtyEntries++] = rep;
6906 This->isStateDirty[idx] |= (1 << shift);