wined3d: Break the lighting state out of the vertex decl.
[wine.git] / dlls / wined3d / device.c
blobf205db982d142bffbd61ca2e7800431cc14f944e
1 /*
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
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
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 */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
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 )
66 Display *display;
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;
71 return display;
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);
82 /* helper macros */
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; \
91 object->ref = 1; \
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; \
100 object->ref = 1; \
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); \
122 *pp##type = NULL; \
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); \
131 *pp##type = NULL; \
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) {
157 float quad_att;
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);
163 glPushMatrix();
164 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
166 /* Diffuse: */
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");
174 /* Specular */
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");
182 /* Ambient */
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);
198 } else {
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:
208 /* Position */
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");
213 /* FIXME: Range */
214 break;
216 case WINED3DLIGHT_SPOT:
217 /* Position */
218 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
219 checkGLcall("glLightfv");
220 /* Direction */
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");
227 /* FIXME: Range */
228 break;
230 case WINED3DLIGHT_DIRECTIONAL:
231 /* Direction */
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");
238 break;
240 default:
241 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
244 /* Restore the modelview matrix */
245 glPopMatrix();
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;
269 if (obj != 0) {
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;
286 int numAttached = 0;
287 int i;
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 );
292 while (ptr) {
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);
331 *ppobj = This;
332 return S_OK;
334 *ppobj = NULL;
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);
343 return refCount;
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);
352 if (!refCount) {
353 if (This->fbo) {
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);
398 This = NULL;
400 return refCount;
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);
410 return WINED3D_OK;
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");
419 return;
422 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
424 ENTER_GL();
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);
443 goto 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);
450 goto 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;
471 break;
472 case D3DUSAGE_WRITEONLY:
473 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
474 glUsage = GL_DYNAMIC_DRAW_ARB;
475 break;
476 case D3DUSAGE_DYNAMIC:
477 TRACE("Gl usage = GL_STREAM_COPY\n");
478 glUsage = GL_STREAM_COPY_ARB;
479 break;
480 default:
481 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
482 glUsage = GL_DYNAMIC_COPY_ARB;
483 break;
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);
494 goto error;
497 LEAVE_GL();
499 return;
500 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));
504 object->vbo = 0;
505 object->Flags |= VBFLAG_VBOCREATEFAIL;
506 LEAVE_GL();
507 return;
510 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
511 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
512 IUnknown *parent) {
513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
514 IWineD3DVertexBufferImpl *object;
515 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
516 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
517 BOOL conv;
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);
528 object->fvf = FVF;
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
541 * dx7 apps.
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) ) {
548 CreateVBO(object);
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;
557 return WINED3D_OK;
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)
570 /*TODO: use VBO's */
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;
579 return WINED3D_OK;
582 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
585 IWineD3DStateBlockImpl *object;
586 int i, j;
587 HRESULT temp_result;
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 */
597 return WINED3D_OK;
600 temp_result = allocate_shader_constants(object);
601 if (WINED3D_OK != temp_result)
602 return 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);
607 else
608 memset(object->streamFreq, 1, sizeof(object->streamFreq));
610 /* Reset the ref and type after kludging it */
611 object->wineD3DDevice = This;
612 object->ref = 1;
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;
690 while (src) {
691 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
692 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
693 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
694 newEl->prev = dst;
695 newEl->changed = TRUE;
696 newEl->enabledChanged = TRUE;
697 if (dst == NULL) {
698 object->lights = newEl;
699 } else {
700 dst->next = newEl;
702 dst = newEl;
703 src = src->next;
708 } else {
709 FIXME("Unrecognized state block type %d\n", Type);
712 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
713 return WINED3D_OK;
717 /* ************************************
718 MSDN:
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.
721 Discard
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
737 * MSDN
738 * MultisampleQuality
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
743 * must all match.
744 *******************************/
748 * TODO: Discard MSDN
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
769 * by the device.
770 *******************************/
772 /* Non-power2 support */
773 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
774 pow2Width = Width;
775 pow2Height = Height;
776 } else {
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
795 * space!
796 *********************************/
797 if (WINED3DFMT_UNKNOWN == Format) {
798 Size = 0;
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));
806 } else {
807 /* The pitch is a multiple of 4 bytes */
808 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
809 Size *= pow2Height;
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;
831 /* Internal data */
832 object->pow2Width = pow2Width;
833 object->pow2Height = pow2Height;
835 /* Flags */
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;
847 } else {
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 * ****************************************/
860 switch(Pool) {
861 case WINED3DPOOL_SCRATCH:
862 if(!Lockable)
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");
865 Lockable = TRUE;
866 break;
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");
874 break;
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");
879 break;
880 default:
881 FIXME("(%p) Unknown pool %d\n", This, Pool);
882 break;
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 */
900 switch(Impl) {
901 case SURFACE_OPENGL:
902 /* Nothing to do, it's set already */
903 break;
905 case SURFACE_GDI:
906 object->lpVtbl = &IWineGDISurface_Vtbl;
907 break;
909 default:
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;
928 unsigned int i;
929 UINT tmpW;
930 UINT tmpH;
931 HRESULT hr;
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) {
954 pow2Width = Width;
955 pow2Height = Height;
956 } else {
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 */
970 if (Levels == 0) {
971 TRACE("calculating levels %d\n", object->baseTexture.levels);
972 object->baseTexture.levels++;
973 tmpW = Width;
974 tmpH = Height;
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 */
984 tmpW = Width;
985 tmpH = Height;
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);
992 /* clean up */
993 object->surfaces[i] = NULL;
994 IWineD3DTexture_Release((IWineD3DTexture *)object);
996 *ppTexture = NULL;
997 return hr;
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);
1008 return WINED3D_OK;
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;
1021 unsigned int i;
1022 UINT tmpW;
1023 UINT tmpH;
1024 UINT tmpD;
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 */
1044 if (Levels == 0) {
1045 object->baseTexture.levels++;
1046 tmpW = Width;
1047 tmpH = Height;
1048 tmpD = Depth;
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 */
1059 tmpW = Width;
1060 tmpH = Height;
1061 tmpD = Depth;
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);
1080 return WINED3D_OK;
1083 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1084 UINT Width, UINT Height, UINT Depth,
1085 DWORD Usage,
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 **/
1122 unsigned int i, j;
1123 UINT tmpW;
1124 HRESULT hr;
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 */
1142 pow2EdgeLength = 1;
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 */
1151 if (Levels == 0) {
1152 object->baseTexture.levels++;
1153 tmpW = EdgeLength;
1154 while (tmpW > 1) {
1155 tmpW = max(1, tmpW >> 1);
1156 object->baseTexture.levels++;
1158 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1161 /* Generate all the surfaces */
1162 tmpW = EdgeLength;
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) {
1172 /* clean up */
1173 int k;
1174 int l;
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;
1187 return hr;
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;
1197 return WINED3D_OK;
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;
1207 switch(Type) {
1208 case WINED3DQUERYTYPE_OCCLUSION:
1209 TRACE("(%p) occlusion query\n", This);
1210 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1211 hr = WINED3D_OK;
1212 else
1213 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1214 break;
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:
1228 default:
1229 FIXME("(%p) Unhandled query type %d\n", This, Type);
1231 return hr;
1234 D3DCREATEOBJECTINSTANCE(object, Query)
1235 object->type = Type;
1236 /* allocated the 'extended' data based on the type of query requested */
1237 switch(Type){
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));
1243 break;
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:
1258 default:
1259 object->extendedData = 0;
1260 FIXME("(%p) Unhandled query type %d\n",This , Type);
1262 TRACE("(%p) : Created Query %p\n", This, object);
1263 return WINED3D_OK;
1266 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1268 IUnknown* parent,
1269 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1270 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 HDC hDc;
1274 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1275 int num;
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 **/
1340 ENTER_GL();
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");
1351 LEAVE_GL();
1352 return WINED3DERR_NOTAVAILABLE;
1353 } else {
1354 int n, value;
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 **/
1393 #endif
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);
1401 } else {
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);
1411 /* Cleanup */
1412 XFree(object->visInfo);
1413 object->visInfo = NULL;
1415 LEAVE_GL();
1417 if (!object->glCtx) {
1418 ERR("Failed to create GLX context\n");
1419 return WINED3DERR_NOTAVAILABLE;
1420 } else {
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)) {
1437 DEVMODEW devmode;
1438 HDC hdc;
1439 int bpp = 0;
1440 RECT clip_rc;
1442 /* Get info on the current display setup */
1443 hdc = GetDC(0);
1444 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1445 ReleaseDC(0, hdc);
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))) {
1482 RECT Rect;
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,
1523 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) {
1536 int i;
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,
1557 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);
1568 } else {
1569 break;
1572 } else {
1573 object->backBuffer = NULL;
1576 if (object->backBuffer != NULL) {
1577 ENTER_GL();
1578 glDrawBuffer(GL_BACK);
1579 checkGLcall("glDrawBuffer(GL_BACK)");
1580 LEAVE_GL();
1581 } else {
1582 /* Single buffering - draw to front buffer */
1583 ENTER_GL();
1584 glDrawBuffer(GL_FRONT);
1585 checkGLcall("glDrawBuffer(GL_FRONT)");
1586 LEAVE_GL();
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,
1594 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;
1611 } else {
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 *******************/
1628 ENTER_GL();
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");
1643 glClearIndex(0);
1644 glClearDepth(1);
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);");
1676 LEAVE_GL();
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) {
1690 int i;
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);
1716 return hr;
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);
1735 return WINED3D_OK;
1736 } else {
1737 TRACE("Swapchain out of range\n");
1738 *pSwapChain = NULL;
1739 return WINED3DERR_INVALIDCALL;
1743 /*****
1744 * Vertex Declaration
1745 *****/
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)
1752 object->allFVF = 0;
1754 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1756 return hr;
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;
1777 } else {
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) {
1794 /* Foo */
1795 } else {
1796 /* Bar */
1799 #endif
1801 return WINED3D_OK;
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);
1814 } else {
1815 WARN("(%p) : Failed to create pixel shader\n", This);
1818 return hr;
1821 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1823 IWineD3DPaletteImpl *object;
1824 HRESULT hr;
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));
1829 if(!object) {
1830 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1831 return E_OUTOFMEMORY;
1834 object->lpVtbl = &IWineD3DPalette_Vtbl;
1835 object->ref = 1;
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));
1843 if(!object->hpal) {
1844 HeapFree( GetProcessHeap(), 0, object);
1845 return E_OUTOFMEMORY;
1848 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1849 if(FAILED(hr)) {
1850 IWineD3DPalette_Release((IWineD3DPalette *) object);
1851 return hr;
1854 *Palette = (IWineD3DPalette *) object;
1856 return WINED3D_OK;
1859 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1861 IWineD3DSwapChainImpl *swapchain;
1862 DWORD state;
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];
1895 else {
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 */
1910 ENTER_GL();
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);
1919 #if 0
1920 IWineD3DImpl_CheckGraphicsMemory();
1921 #endif
1922 LEAVE_GL();
1924 /* Initialize our list of GLSL programs */
1925 list_init(&This->glsl_shader_progs);
1927 { /* Set a default viewport */
1928 WINED3DVIEWPORT vp;
1929 vp.X = 0;
1930 vp.Y = 0;
1931 vp.Width = *(pPresentationParameters->BackBufferWidth);
1932 vp.Height = *(pPresentationParameters->BackBufferHeight);
1933 vp.MinZ = 0.0f;
1934 vp.MaxZ = 1.0f;
1935 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1938 /* Initialize the current view state */
1939 This->proj_valid = 0;
1940 This->view_ident = 1;
1941 This->last_was_rhw = 0;
1942 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1943 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1945 /* Clear the screen */
1946 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1948 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
1949 * This might create a problem in 2 situations:
1950 * ->The D3D default value is 0, but the opengl default value is something else
1951 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
1953 for(state = 0; state <= STATE_HIGHEST; state++) {
1954 IWineD3DDeviceImpl_MarkStateDirty(This, state);
1957 This->d3d_initialized = TRUE;
1958 return WINED3D_OK;
1961 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1963 int sampler;
1964 uint i;
1965 TRACE("(%p)\n", This);
1967 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1969 /* Delete the mouse cursor texture */
1970 if(This->cursorTexture) {
1971 ENTER_GL();
1972 glDeleteTextures(1, &This->cursorTexture);
1973 LEAVE_GL();
1974 This->cursorTexture = 0;
1977 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1978 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1981 /* Release the buffers (with sanity checks)*/
1982 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1983 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1984 if(This->depthStencilBuffer != This->stencilBufferTarget)
1985 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1987 This->stencilBufferTarget = NULL;
1989 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1990 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1991 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1993 TRACE("Setting rendertarget to NULL\n");
1994 This->render_targets[0] = NULL;
1996 if (This->depthStencilBuffer) {
1997 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1998 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2000 This->depthStencilBuffer = NULL;
2003 for(i=0; i < This->NumberOfSwapChains; i++) {
2004 TRACE("Releasing the implicit swapchain %d\n", i);
2005 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2006 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2010 HeapFree(GetProcessHeap(), 0, This->swapchains);
2011 This->swapchains = NULL;
2012 This->NumberOfSwapChains = 0;
2014 This->d3d_initialized = FALSE;
2015 return WINED3D_OK;
2018 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2020 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2022 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2023 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2024 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2025 * separately.
2027 This->ddraw_fullscreen = fullscreen;
2030 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2033 DEVMODEW DevModeW;
2034 int i;
2035 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2037 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2039 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2040 /* Ignore some modes if a description was passed */
2041 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2042 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2043 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2045 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2047 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2048 return D3D_OK;
2051 return D3D_OK;
2054 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2055 DEVMODEW devmode;
2056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2057 LONG ret;
2058 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2059 RECT clip_rc;
2061 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2063 /* Resize the screen even without a window:
2064 * The app could have unset it with SetCooperativeLevel, but not called
2065 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2066 * but we don't have any hwnd
2069 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2070 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2071 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2072 devmode.dmPelsWidth = pMode->Width;
2073 devmode.dmPelsHeight = pMode->Height;
2075 devmode.dmDisplayFrequency = pMode->RefreshRate;
2076 if (pMode->RefreshRate != 0) {
2077 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2080 /* Only change the mode if necessary */
2081 if( (This->ddraw_width == pMode->Width) &&
2082 (This->ddraw_height == pMode->Height) &&
2083 (This->ddraw_format == pMode->Format) &&
2084 (pMode->RefreshRate == 0) ) {
2085 return D3D_OK;
2088 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2089 if (ret != DISP_CHANGE_SUCCESSFUL) {
2090 if(devmode.dmDisplayFrequency != 0) {
2091 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2092 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2093 devmode.dmDisplayFrequency = 0;
2094 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2096 if(ret != DISP_CHANGE_SUCCESSFUL) {
2097 return DDERR_INVALIDMODE;
2101 /* Store the new values */
2102 This->ddraw_width = pMode->Width;
2103 This->ddraw_height = pMode->Height;
2104 This->ddraw_format = pMode->Format;
2106 /* Only do this with a window of course */
2107 if(This->ddraw_window)
2108 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2110 /* And finally clip mouse to our screen */
2111 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2112 ClipCursor(&clip_rc);
2114 return WINED3D_OK;
2117 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2119 *ppD3D= This->wineD3D;
2120 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2121 IWineD3D_AddRef(*ppD3D);
2122 return WINED3D_OK;
2125 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2126 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2127 * into the video ram as possible and seeing how many fit
2128 * you can also get the correct initial value from nvidia and ATI's driver via X
2129 * texture memory is video memory + AGP memory
2130 *******************/
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2132 static BOOL showfixmes = TRUE;
2133 if (showfixmes) {
2134 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2135 (wined3d_settings.emulated_textureram/(1024*1024)),
2136 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2137 showfixmes = FALSE;
2139 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2140 (wined3d_settings.emulated_textureram/(1024*1024)),
2141 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2142 /* return simulated texture memory left */
2143 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2148 /*****
2149 * Get / Set FVF
2150 *****/
2151 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 /* Update the current state block */
2155 This->updateStateBlock->fvf = fvf;
2156 This->updateStateBlock->changed.fvf = TRUE;
2157 This->updateStateBlock->set.fvf = TRUE;
2159 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2161 return WINED3D_OK;
2165 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2167 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2168 *pfvf = This->stateBlock->fvf;
2169 return WINED3D_OK;
2172 /*****
2173 * Get / Set Stream Source
2174 *****/
2175 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2177 IWineD3DVertexBuffer *oldSrc;
2179 /**TODO: instance and index data, see
2180 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2182 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2183 **************/
2185 /* D3d9 only, but shouldn't hurt d3d8 */
2186 UINT streamFlags;
2188 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2189 if (streamFlags) {
2190 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2191 FIXME("stream index data not supported\n");
2193 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2194 FIXME("stream instance data not supported\n");
2198 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2200 if (StreamNumber >= MAX_STREAMS) {
2201 WARN("Stream out of range %d\n", StreamNumber);
2202 return WINED3DERR_INVALIDCALL;
2205 oldSrc = This->stateBlock->streamSource[StreamNumber];
2206 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2208 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2209 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2210 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2211 if (pStreamData) {
2212 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2213 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2215 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2217 /* Handle recording of state blocks */
2218 if (This->isRecordingState) {
2219 TRACE("Recording... not performing anything\n");
2220 return WINED3D_OK;
2223 /* Same stream object: no action */
2224 if (oldSrc == pStreamData)
2225 return WINED3D_OK;
2227 /* Need to do a getParent and pass the reffs up */
2228 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2229 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2230 so for now, just count internally */
2231 if (pStreamData != NULL) {
2232 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2233 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2234 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2236 vbImpl->stream = StreamNumber;
2237 vbImpl->Flags |= VBFLAG_STREAM;
2238 IWineD3DVertexBuffer_AddRef(pStreamData);
2240 if (oldSrc != NULL) {
2241 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2242 IWineD3DVertexBuffer_Release(oldSrc);
2245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2247 return WINED3D_OK;
2250 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 UINT streamFlags;
2254 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2255 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2258 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2259 if (streamFlags) {
2260 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2261 FIXME("stream index data not supported\n");
2263 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2264 FIXME("stream instance data not supported\n");
2268 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2270 if (StreamNumber >= MAX_STREAMS) {
2271 WARN("Stream out of range %d\n", StreamNumber);
2272 return WINED3DERR_INVALIDCALL;
2274 *pStream = This->stateBlock->streamSource[StreamNumber];
2275 *pStride = This->stateBlock->streamStride[StreamNumber];
2276 if (pOffset) {
2277 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2280 if (*pStream != NULL) {
2281 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2283 return WINED3D_OK;
2286 /*Should be quite easy, just an extension of vertexdata
2287 ref...
2288 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2290 The divider is a bit odd though
2292 VertexOffset = StartVertex / Divider * StreamStride +
2293 VertexIndex / Divider * StreamStride + StreamOffset
2296 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2300 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2302 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2303 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2304 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2306 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2307 FIXME("Stream indexing not fully supported\n");
2310 return WINED3D_OK;
2313 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2317 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2319 TRACE("(%p) : returning %d\n", This, *Divider);
2321 return WINED3D_OK;
2324 /*****
2325 * Get / Set & Multiply Transform
2326 *****/
2327 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330 /* Most of this routine, comments included copied from ddraw tree initially: */
2331 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2333 /* Handle recording of state blocks */
2334 if (This->isRecordingState) {
2335 TRACE("Recording... not performing anything\n");
2336 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2337 This->updateStateBlock->set.transform[d3dts] = TRUE;
2338 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2339 return WINED3D_OK;
2343 * If the new matrix is the same as the current one,
2344 * we cut off any further processing. this seems to be a reasonable
2345 * optimization because as was noticed, some apps (warcraft3 for example)
2346 * tend towards setting the same matrix repeatedly for some reason.
2348 * From here on we assume that the new matrix is different, wherever it matters.
2350 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2351 TRACE("The app is setting the same matrix over again\n");
2352 return WINED3D_OK;
2353 } else {
2354 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2358 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2359 where ViewMat = Camera space, WorldMat = world space.
2361 In OpenGL, camera and world space is combined into GL_MODELVIEW
2362 matrix. The Projection matrix stay projection matrix.
2365 /* Capture the times we can just ignore the change for now */
2366 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2367 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2368 /* Handled by the state manager */
2371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2372 return WINED3D_OK;
2375 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2377 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2378 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2379 return WINED3D_OK;
2382 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2383 WINED3DMATRIX *mat = NULL;
2384 WINED3DMATRIX temp;
2386 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2387 * below means it will be recorded in a state block change, but it
2388 * works regardless where it is recorded.
2389 * If this is found to be wrong, change to StateBlock.
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2394 if (State < HIGHEST_TRANSFORMSTATE)
2396 mat = &This->updateStateBlock->transforms[State];
2397 } else {
2398 FIXME("Unhandled transform state!!\n");
2401 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2403 /* Apply change via set transform - will reapply to eg. lights this way */
2404 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2407 /*****
2408 * Get / Set Light
2409 *****/
2410 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2411 you can reference any indexes you want as long as that number max are enabled at any
2412 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2413 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2414 but when recording, just build a chain pretty much of commands to be replayed. */
2416 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2417 float rho;
2418 PLIGHTINFOEL *object, *temp;
2420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2423 /* If recording state block, just add to end of lights chain */
2424 if (This->isRecordingState) {
2425 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2426 if (NULL == object) {
2427 return WINED3DERR_OUTOFVIDEOMEMORY;
2429 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2430 object->OriginalIndex = Index;
2431 object->glIndex = -1;
2432 object->changed = TRUE;
2434 /* Add to the END of the chain of lights changes to be replayed */
2435 if (This->updateStateBlock->lights == NULL) {
2436 This->updateStateBlock->lights = object;
2437 } else {
2438 temp = This->updateStateBlock->lights;
2439 while (temp->next != NULL) temp=temp->next;
2440 temp->next = object;
2442 TRACE("Recording... not performing anything more\n");
2443 return WINED3D_OK;
2446 /* Ok, not recording any longer so do real work */
2447 object = This->stateBlock->lights;
2448 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2450 /* If we didn't find it in the list of lights, time to add it */
2451 if (object == NULL) {
2452 PLIGHTINFOEL *insertAt,*prevPos;
2454 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2455 if (NULL == object) {
2456 return WINED3DERR_OUTOFVIDEOMEMORY;
2458 object->OriginalIndex = Index;
2459 object->glIndex = -1;
2461 /* Add it to the front of list with the idea that lights will be changed as needed
2462 BUT after any lights currently assigned GL indexes */
2463 insertAt = This->stateBlock->lights;
2464 prevPos = NULL;
2465 while (insertAt != NULL && insertAt->glIndex != -1) {
2466 prevPos = insertAt;
2467 insertAt = insertAt->next;
2470 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2471 This->stateBlock->lights = object;
2472 } else if (insertAt == NULL) { /* End of list */
2473 prevPos->next = object;
2474 object->prev = prevPos;
2475 } else { /* Middle of chain */
2476 if (prevPos == NULL) {
2477 This->stateBlock->lights = object;
2478 } else {
2479 prevPos->next = object;
2481 object->prev = prevPos;
2482 object->next = insertAt;
2483 insertAt->prev = object;
2487 /* Initialize the object */
2488 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,
2489 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2490 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2491 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2492 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2493 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2494 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2496 /* Save away the information */
2497 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2499 switch (pLight->Type) {
2500 case WINED3DLIGHT_POINT:
2501 /* Position */
2502 object->lightPosn[0] = pLight->Position.x;
2503 object->lightPosn[1] = pLight->Position.y;
2504 object->lightPosn[2] = pLight->Position.z;
2505 object->lightPosn[3] = 1.0f;
2506 object->cutoff = 180.0f;
2507 /* FIXME: Range */
2508 break;
2510 case WINED3DLIGHT_DIRECTIONAL:
2511 /* Direction */
2512 object->lightPosn[0] = -pLight->Direction.x;
2513 object->lightPosn[1] = -pLight->Direction.y;
2514 object->lightPosn[2] = -pLight->Direction.z;
2515 object->lightPosn[3] = 0.0;
2516 object->exponent = 0.0f;
2517 object->cutoff = 180.0f;
2518 break;
2520 case WINED3DLIGHT_SPOT:
2521 /* Position */
2522 object->lightPosn[0] = pLight->Position.x;
2523 object->lightPosn[1] = pLight->Position.y;
2524 object->lightPosn[2] = pLight->Position.z;
2525 object->lightPosn[3] = 1.0;
2527 /* Direction */
2528 object->lightDirn[0] = pLight->Direction.x;
2529 object->lightDirn[1] = pLight->Direction.y;
2530 object->lightDirn[2] = pLight->Direction.z;
2531 object->lightDirn[3] = 1.0;
2534 * opengl-ish and d3d-ish spot lights use too different models for the
2535 * light "intensity" as a function of the angle towards the main light direction,
2536 * so we only can approximate very roughly.
2537 * however spot lights are rather rarely used in games (if ever used at all).
2538 * furthermore if still used, probably nobody pays attention to such details.
2540 if (pLight->Falloff == 0) {
2541 rho = 6.28f;
2542 } else {
2543 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2545 if (rho < 0.0001) rho = 0.0001f;
2546 object->exponent = -0.3/log(cos(rho/2));
2547 if (object->exponent > 128.0) {
2548 object->exponent = 128.0;
2550 object->cutoff = pLight->Phi*90/M_PI;
2552 /* FIXME: Range */
2553 break;
2555 default:
2556 FIXME("Unrecognized light type %d\n", pLight->Type);
2559 /* Update the live definitions if the light is currently assigned a glIndex */
2560 if (object->glIndex != -1) {
2561 setup_light(iface, object->glIndex, object);
2563 return WINED3D_OK;
2566 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2567 PLIGHTINFOEL *lightInfo = NULL;
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2569 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2571 /* Locate the light in the live lights */
2572 lightInfo = This->stateBlock->lights;
2573 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2575 if (lightInfo == NULL) {
2576 TRACE("Light information requested but light not defined\n");
2577 return WINED3DERR_INVALIDCALL;
2580 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2581 return WINED3D_OK;
2584 /*****
2585 * Get / Set Light Enable
2586 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2587 *****/
2588 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2589 PLIGHTINFOEL *lightInfo = NULL;
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2593 /* Tests show true = 128...not clear why */
2595 Enable = Enable? 128: 0;
2597 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2598 if (This->isRecordingState) {
2599 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2600 if (NULL == lightInfo) {
2601 return WINED3DERR_OUTOFVIDEOMEMORY;
2603 lightInfo->OriginalIndex = Index;
2604 lightInfo->glIndex = -1;
2605 lightInfo->enabledChanged = TRUE;
2606 lightInfo->lightEnabled = Enable;
2608 /* Add to the END of the chain of lights changes to be replayed */
2609 if (This->updateStateBlock->lights == NULL) {
2610 This->updateStateBlock->lights = lightInfo;
2611 } else {
2612 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2613 while (temp->next != NULL) temp=temp->next;
2614 temp->next = lightInfo;
2616 TRACE("Recording... not performing anything more\n");
2617 return WINED3D_OK;
2620 /* Not recording... So, locate the light in the live lights */
2621 lightInfo = This->stateBlock->lights;
2622 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2624 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2625 if (lightInfo == NULL) {
2627 TRACE("Light enabled requested but light not defined, so defining one!\n");
2628 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2630 /* Search for it again! Should be fairly quick as near head of list */
2631 lightInfo = This->stateBlock->lights;
2632 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2633 if (lightInfo == NULL) {
2634 FIXME("Adding default lights has failed dismally\n");
2635 return WINED3DERR_INVALIDCALL;
2639 /* OK, we now have a light... */
2640 if (!Enable) {
2642 /* If we are disabling it, check it was enabled, and
2643 still only do something if it has assigned a glIndex (which it should have!) */
2644 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2645 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2646 ENTER_GL();
2647 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2648 checkGLcall("glDisable GL_LIGHT0+Index");
2649 LEAVE_GL();
2650 } else {
2651 TRACE("Nothing to do as light was not enabled\n");
2653 lightInfo->lightEnabled = Enable;
2654 } else {
2656 /* We are enabling it. If it is enabled, it's really simple */
2657 if (lightInfo->lightEnabled) {
2658 /* nop */
2659 TRACE("Nothing to do as light was enabled\n");
2661 /* If it already has a glIndex, it's still simple */
2662 } else if (lightInfo->glIndex != -1) {
2663 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2664 lightInfo->lightEnabled = Enable;
2665 ENTER_GL();
2666 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2667 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2668 LEAVE_GL();
2670 /* Otherwise got to find space - lights are ordered gl indexes first */
2671 } else {
2672 PLIGHTINFOEL *bsf = NULL;
2673 PLIGHTINFOEL *pos = This->stateBlock->lights;
2674 PLIGHTINFOEL *prev = NULL;
2675 int Index= 0;
2676 int glIndex = -1;
2678 /* Try to minimize changes as much as possible */
2679 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2681 /* Try to remember which index can be replaced if necessary */
2682 if (bsf==NULL && !pos->lightEnabled) {
2683 /* Found a light we can replace, save as best replacement */
2684 bsf = pos;
2687 /* Step to next space */
2688 prev = pos;
2689 pos = pos->next;
2690 Index ++;
2693 /* If we have too many active lights, fail the call */
2694 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2695 FIXME("Program requests too many concurrent lights\n");
2696 return WINED3DERR_INVALIDCALL;
2698 /* If we have allocated all lights, but not all are enabled,
2699 reuse one which is not enabled */
2700 } else if (Index == This->maxConcurrentLights) {
2701 /* use bsf - Simply swap the new light and the BSF one */
2702 PLIGHTINFOEL *bsfNext = bsf->next;
2703 PLIGHTINFOEL *bsfPrev = bsf->prev;
2705 /* Sort out ends */
2706 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2707 if (bsf->prev != NULL) {
2708 bsf->prev->next = lightInfo;
2709 } else {
2710 This->stateBlock->lights = lightInfo;
2713 /* If not side by side, lots of chains to update */
2714 if (bsf->next != lightInfo) {
2715 lightInfo->prev->next = bsf;
2716 bsf->next->prev = lightInfo;
2717 bsf->next = lightInfo->next;
2718 bsf->prev = lightInfo->prev;
2719 lightInfo->next = bsfNext;
2720 lightInfo->prev = bsfPrev;
2722 } else {
2723 /* Simple swaps */
2724 bsf->prev = lightInfo;
2725 bsf->next = lightInfo->next;
2726 lightInfo->next = bsf;
2727 lightInfo->prev = bsfPrev;
2731 /* Update states */
2732 glIndex = bsf->glIndex;
2733 bsf->glIndex = -1;
2734 lightInfo->glIndex = glIndex;
2735 lightInfo->lightEnabled = Enable;
2737 /* Finally set up the light in gl itself */
2738 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2739 ENTER_GL();
2740 setup_light(iface, glIndex, lightInfo);
2741 glEnable(GL_LIGHT0 + glIndex);
2742 checkGLcall("glEnable GL_LIGHT0 new setup");
2743 LEAVE_GL();
2745 /* If we reached the end of the allocated lights, with space in the
2746 gl lights, setup a new light */
2747 } else if (pos->glIndex == -1) {
2749 /* We reached the end of the allocated gl lights, so already
2750 know the index of the next one! */
2751 glIndex = Index;
2752 lightInfo->glIndex = glIndex;
2753 lightInfo->lightEnabled = Enable;
2755 /* In an ideal world, it's already in the right place */
2756 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2757 /* No need to move it */
2758 } else {
2759 /* Remove this light from the list */
2760 lightInfo->prev->next = lightInfo->next;
2761 if (lightInfo->next != NULL) {
2762 lightInfo->next->prev = lightInfo->prev;
2765 /* Add in at appropriate place (inbetween prev and pos) */
2766 lightInfo->prev = prev;
2767 lightInfo->next = pos;
2768 if (prev == NULL) {
2769 This->stateBlock->lights = lightInfo;
2770 } else {
2771 prev->next = lightInfo;
2773 if (pos != NULL) {
2774 pos->prev = lightInfo;
2778 /* Finally set up the light in gl itself */
2779 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
2780 ENTER_GL();
2781 setup_light(iface, glIndex, lightInfo);
2782 glEnable(GL_LIGHT0 + glIndex);
2783 checkGLcall("glEnable GL_LIGHT0 new setup");
2784 LEAVE_GL();
2789 return WINED3D_OK;
2792 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2794 PLIGHTINFOEL *lightInfo = NULL;
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 TRACE("(%p) : for idx(%d)\n", This, Index);
2798 /* Locate the light in the live lights */
2799 lightInfo = This->stateBlock->lights;
2800 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2802 if (lightInfo == NULL) {
2803 TRACE("Light enabled state requested but light not defined\n");
2804 return WINED3DERR_INVALIDCALL;
2806 *pEnable = lightInfo->lightEnabled;
2807 return WINED3D_OK;
2810 /*****
2811 * Get / Set Clip Planes
2812 *****/
2813 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2815 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2817 /* Validate Index */
2818 if (Index >= GL_LIMITS(clipplanes)) {
2819 TRACE("Application has requested clipplane this device doesn't support\n");
2820 return WINED3DERR_INVALIDCALL;
2823 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2824 This->updateStateBlock->set.clipplane[Index] = TRUE;
2825 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2826 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2827 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2828 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2830 /* Handle recording of state blocks */
2831 if (This->isRecordingState) {
2832 TRACE("Recording... not performing anything\n");
2833 return WINED3D_OK;
2836 /* Apply it */
2838 ENTER_GL();
2840 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2841 glMatrixMode(GL_MODELVIEW);
2842 glPushMatrix();
2843 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2845 TRACE("Clipplane [%f,%f,%f,%f]\n",
2846 This->updateStateBlock->clipplane[Index][0],
2847 This->updateStateBlock->clipplane[Index][1],
2848 This->updateStateBlock->clipplane[Index][2],
2849 This->updateStateBlock->clipplane[Index][3]);
2850 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2851 checkGLcall("glClipPlane");
2853 glPopMatrix();
2854 LEAVE_GL();
2856 return WINED3D_OK;
2859 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2861 TRACE("(%p) : for idx %d\n", This, Index);
2863 /* Validate Index */
2864 if (Index >= GL_LIMITS(clipplanes)) {
2865 TRACE("Application has requested clipplane this device doesn't support\n");
2866 return WINED3DERR_INVALIDCALL;
2869 pPlane[0] = This->stateBlock->clipplane[Index][0];
2870 pPlane[1] = This->stateBlock->clipplane[Index][1];
2871 pPlane[2] = This->stateBlock->clipplane[Index][2];
2872 pPlane[3] = This->stateBlock->clipplane[Index][3];
2873 return WINED3D_OK;
2876 /*****
2877 * Get / Set Clip Plane Status
2878 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2879 *****/
2880 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 FIXME("(%p) : stub\n", This);
2883 if (NULL == pClipStatus) {
2884 return WINED3DERR_INVALIDCALL;
2886 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2887 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2888 return WINED3D_OK;
2891 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 FIXME("(%p) : stub\n", This);
2894 if (NULL == pClipStatus) {
2895 return WINED3DERR_INVALIDCALL;
2897 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2898 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2899 return WINED3D_OK;
2902 /*****
2903 * Get / Set Material
2904 *****/
2905 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2908 This->updateStateBlock->changed.material = TRUE;
2909 This->updateStateBlock->set.material = TRUE;
2910 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2912 /* Handle recording of state blocks */
2913 if (This->isRecordingState) {
2914 TRACE("Recording... not performing anything\n");
2915 return WINED3D_OK;
2918 ENTER_GL();
2919 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2920 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2921 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2922 pMaterial->Ambient.b, pMaterial->Ambient.a);
2923 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2924 pMaterial->Specular.b, pMaterial->Specular.a);
2925 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2926 pMaterial->Emissive.b, pMaterial->Emissive.a);
2927 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2929 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2930 checkGLcall("glMaterialfv(GL_AMBIENT)");
2931 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2932 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2934 /* Only change material color if specular is enabled, otherwise it is set to black */
2935 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2936 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2937 checkGLcall("glMaterialfv(GL_SPECULAR");
2938 } else {
2939 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2940 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2941 checkGLcall("glMaterialfv(GL_SPECULAR");
2943 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2944 checkGLcall("glMaterialfv(GL_EMISSION)");
2945 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2946 checkGLcall("glMaterialf(GL_SHININESS");
2948 LEAVE_GL();
2949 return WINED3D_OK;
2952 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2955 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2956 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2957 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2958 pMaterial->Ambient.b, pMaterial->Ambient.a);
2959 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2960 pMaterial->Specular.b, pMaterial->Specular.a);
2961 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2962 pMaterial->Emissive.b, pMaterial->Emissive.a);
2963 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2965 return WINED3D_OK;
2968 /*****
2969 * Get / Set Indices
2970 *****/
2971 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2972 UINT BaseVertexIndex) {
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 IWineD3DIndexBuffer *oldIdxs;
2975 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2977 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2978 oldIdxs = This->updateStateBlock->pIndexData;
2980 This->updateStateBlock->changed.indices = TRUE;
2981 This->updateStateBlock->set.indices = TRUE;
2982 This->updateStateBlock->pIndexData = pIndexData;
2983 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2985 /* Handle recording of state blocks */
2986 if (This->isRecordingState) {
2987 TRACE("Recording... not performing anything\n");
2988 return WINED3D_OK;
2991 if (NULL != pIndexData) {
2992 IWineD3DIndexBuffer_AddRef(pIndexData);
2994 if (NULL != oldIdxs) {
2995 IWineD3DIndexBuffer_Release(oldIdxs);
2998 /* So far only the base vertex index is tracked */
2999 if(BaseVertexIndex != oldBaseIndex) {
3000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3002 return WINED3D_OK;
3005 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3008 *ppIndexData = This->stateBlock->pIndexData;
3010 /* up ref count on ppindexdata */
3011 if (*ppIndexData) {
3012 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3013 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3014 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3015 }else{
3016 TRACE("(%p) No index data set\n", This);
3018 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3020 return WINED3D_OK;
3023 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3024 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 TRACE("(%p)->(%d)\n", This, BaseIndex);
3028 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3029 TRACE("Application is setting the old value over, nothing to do\n");
3030 return WINED3D_OK;
3033 This->updateStateBlock->baseVertexIndex = BaseIndex;
3035 if (This->isRecordingState) {
3036 TRACE("Recording... not performing anything\n");
3037 return WINED3D_OK;
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3040 return WINED3D_OK;
3043 /*****
3044 * Get / Set Viewports
3045 *****/
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 TRACE("(%p)\n", This);
3050 This->updateStateBlock->changed.viewport = TRUE;
3051 This->updateStateBlock->set.viewport = TRUE;
3052 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3054 /* Handle recording of state blocks */
3055 if (This->isRecordingState) {
3056 TRACE("Recording... not performing anything\n");
3057 return WINED3D_OK;
3059 This->viewport_changed = TRUE;
3061 ENTER_GL();
3063 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3064 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3066 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3067 checkGLcall("glDepthRange");
3068 /* Note: GL requires lower left, DirectX supplies upper left */
3069 /* TODO: replace usage of renderTarget with context management */
3070 glViewport(pViewport->X,
3071 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3072 pViewport->Width, pViewport->Height);
3074 checkGLcall("glViewport");
3076 LEAVE_GL();
3078 /* Todo: move the gl code too */
3079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3080 return WINED3D_OK;
3084 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 TRACE("(%p)\n", This);
3087 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3088 return WINED3D_OK;
3091 /*****
3092 * Get / Set Render States
3093 * TODO: Verify against dx9 definitions
3094 *****/
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 DWORD oldValue = This->stateBlock->renderState[State];
3100 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3102 This->updateStateBlock->changed.renderState[State] = TRUE;
3103 This->updateStateBlock->set.renderState[State] = TRUE;
3104 This->updateStateBlock->renderState[State] = Value;
3106 /* Handle recording of state blocks */
3107 if (This->isRecordingState) {
3108 TRACE("Recording... not performing anything\n");
3109 return WINED3D_OK;
3112 /* Compared here and not before the assignment to allow proper stateblock recording */
3113 if(Value == oldValue) {
3114 TRACE("Application is setting the old value over, nothing to do\n");
3115 } else {
3116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3119 return WINED3D_OK;
3122 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3125 *pValue = This->stateBlock->renderState[State];
3126 return WINED3D_OK;
3129 /*****
3130 * Get / Set Sampler States
3131 * TODO: Verify against dx9 definitions
3132 *****/
3134 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3139 * SetSampler is designed to allow for more than the standard up to 8 textures
3140 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3141 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3143 * http://developer.nvidia.com/object/General_FAQ.html#t6
3145 * There are two new settings for GForce
3146 * the sampler one:
3147 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3148 * and the texture one:
3149 * GL_MAX_TEXTURE_COORDS_ARB.
3150 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3151 ******************/
3152 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
3153 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3154 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3155 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3156 return WINED3DERR_INVALIDCALL;
3159 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3160 debug_d3dsamplerstate(Type), Type, Value);
3161 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3162 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3163 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3165 /* Handle recording of state blocks */
3166 if (This->isRecordingState) {
3167 TRACE("Recording... not performing anything\n");
3168 return WINED3D_OK;
3171 if(oldValue == Value) {
3172 TRACE("Application is setting the old value over, nothing to do\n");
3173 return WINED3D_OK;
3176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3178 return WINED3D_OK;
3181 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 /** TODO: check that sampler is in range **/
3184 *Value = This->stateBlock->samplerState[Sampler][Type];
3185 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 RECT windowRect;
3193 UINT winHeight;
3195 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3196 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3197 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3199 winHeight = windowRect.bottom - windowRect.top;
3200 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3201 pRect->right - pRect->left, pRect->bottom - pRect->top);
3202 ENTER_GL();
3203 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3204 checkGLcall("glScissor");
3205 LEAVE_GL();
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 GLint scissorBox[4];
3214 ENTER_GL();
3215 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3216 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3217 pRect->left = scissorBox[0];
3218 pRect->top = scissorBox[1];
3219 pRect->right = scissorBox[0] + scissorBox[2];
3220 pRect->bottom = scissorBox[1] + scissorBox[3];
3221 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3222 LEAVE_GL();
3223 return WINED3D_OK;
3226 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3228 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3230 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3232 This->updateStateBlock->vertexDecl = pDecl;
3233 This->updateStateBlock->changed.vertexDecl = TRUE;
3234 This->updateStateBlock->set.vertexDecl = TRUE;
3236 if (This->isRecordingState) {
3237 TRACE("Recording... not performing anything\n");
3240 if (NULL != pDecl) {
3241 IWineD3DVertexDeclaration_AddRef(pDecl);
3243 if (NULL != oldDecl) {
3244 IWineD3DVertexDeclaration_Release(oldDecl);
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3247 return WINED3D_OK;
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3255 *ppDecl = This->stateBlock->vertexDecl;
3256 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3262 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3264 This->updateStateBlock->vertexShader = pShader;
3265 This->updateStateBlock->changed.vertexShader = TRUE;
3266 This->updateStateBlock->set.vertexShader = TRUE;
3268 if (This->isRecordingState) {
3269 TRACE("Recording... not performing anything\n");
3272 if (NULL != pShader) {
3273 IWineD3DVertexShader_AddRef(pShader);
3275 if (NULL != oldShader) {
3276 IWineD3DVertexShader_Release(oldShader);
3279 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3283 return WINED3D_OK;
3286 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3289 if (NULL == ppShader) {
3290 return WINED3DERR_INVALIDCALL;
3292 *ppShader = This->stateBlock->vertexShader;
3293 if( NULL != *ppShader)
3294 IWineD3DVertexShader_AddRef(*ppShader);
3296 TRACE("(%p) : returning %p\n", This, *ppShader);
3297 return WINED3D_OK;
3300 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3301 IWineD3DDevice *iface,
3302 UINT start,
3303 CONST BOOL *srcData,
3304 UINT count) {
3306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 int i, cnt = min(count, MAX_CONST_B - start);
3309 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3310 iface, srcData, start, count);
3312 if (srcData == NULL || cnt < 0)
3313 return WINED3DERR_INVALIDCALL;
3315 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3316 for (i = 0; i < cnt; i++)
3317 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3319 for (i = start; i < cnt + start; ++i) {
3320 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3321 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3324 return WINED3D_OK;
3327 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3328 IWineD3DDevice *iface,
3329 UINT start,
3330 BOOL *dstData,
3331 UINT count) {
3333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3334 int cnt = min(count, MAX_CONST_B - start);
3336 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3337 iface, dstData, start, count);
3339 if (dstData == NULL || cnt < 0)
3340 return WINED3DERR_INVALIDCALL;
3342 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3343 return WINED3D_OK;
3346 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3347 IWineD3DDevice *iface,
3348 UINT start,
3349 CONST int *srcData,
3350 UINT count) {
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3353 int i, cnt = min(count, MAX_CONST_I - start);
3355 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3356 iface, srcData, start, count);
3358 if (srcData == NULL || cnt < 0)
3359 return WINED3DERR_INVALIDCALL;
3361 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3362 for (i = 0; i < cnt; i++)
3363 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3364 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3366 for (i = start; i < cnt + start; ++i) {
3367 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3368 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3371 return WINED3D_OK;
3374 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3375 IWineD3DDevice *iface,
3376 UINT start,
3377 int *dstData,
3378 UINT count) {
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 int cnt = min(count, MAX_CONST_I - start);
3383 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3384 iface, dstData, start, count);
3386 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3387 return WINED3DERR_INVALIDCALL;
3389 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3390 return WINED3D_OK;
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3394 IWineD3DDevice *iface,
3395 UINT start,
3396 CONST float *srcData,
3397 UINT count) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3402 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3403 iface, srcData, start, count);
3405 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3406 return WINED3DERR_INVALIDCALL;
3408 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3409 for (i = 0; i < cnt; i++)
3410 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3411 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3413 for (i = start; i < cnt + start; ++i) {
3414 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3415 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3416 ptr->idx = i;
3417 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3418 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3420 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3427 IWineD3DDevice *iface,
3428 UINT start,
3429 float *dstData,
3430 UINT count) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3435 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3436 iface, dstData, start, count);
3438 if (dstData == NULL || cnt < 0)
3439 return WINED3DERR_INVALIDCALL;
3441 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3442 return WINED3D_OK;
3445 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3446 DWORD i;
3447 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3452 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3453 DWORD i, tex;
3454 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3455 * it is never called.
3457 * Rules are:
3458 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3459 * that would be really messy and require shader recompilation
3460 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3461 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3462 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3463 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3465 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3466 if(This->oneToOneTexUnitMap) {
3467 TRACE("Not touching 1:1 map\n");
3468 return;
3470 TRACE("Restoring 1:1 texture unit mapping\n");
3471 /* Restore a 1:1 mapping */
3472 for(i = 0; i < MAX_SAMPLERS; i++) {
3473 if(This->texUnitMap[i] != i) {
3474 This->texUnitMap[i] = i;
3475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3476 markTextureStagesDirty(This, i);
3479 This->oneToOneTexUnitMap = TRUE;
3480 return;
3481 } else {
3482 /* No pixel shader, and we do not have enought texture units available. Try to skip NULL textures
3483 * First, see if we can succeed at all
3485 tex = 0;
3486 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3487 if(This->stateBlock->textures[i] == NULL) tex++;
3490 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3491 FIXME("Too many bound textures to support the combiner settings\n");
3492 return;
3495 /* Now work out the mapping */
3496 tex = 0;
3497 This->oneToOneTexUnitMap = FALSE;
3498 WARN("Non 1:1 mapping UNTESTED!\n");
3499 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3500 /* Skip NULL textures */
3501 if (!This->stateBlock->textures[i]) {
3502 /* Map to -1, so the check below doesn't fail if a non-NULL
3503 * texture is set on this stage */
3504 TRACE("Mapping texture stage %d to -1\n", i);
3505 This->texUnitMap[i] = -1;
3507 continue;
3510 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3511 if(This->texUnitMap[i] != tex) {
3512 This->texUnitMap[i] = tex;
3513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3514 markTextureStagesDirty(This, i);
3517 ++tex;
3522 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3524 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3525 This->updateStateBlock->pixelShader = pShader;
3526 This->updateStateBlock->changed.pixelShader = TRUE;
3527 This->updateStateBlock->set.pixelShader = TRUE;
3529 /* Handle recording of state blocks */
3530 if (This->isRecordingState) {
3531 TRACE("Recording... not performing anything\n");
3534 if (NULL != pShader) {
3535 IWineD3DPixelShader_AddRef(pShader);
3537 if (NULL != oldShader) {
3538 IWineD3DPixelShader_Release(oldShader);
3541 if (This->isRecordingState) {
3542 TRACE("Recording... not performing anything\n");
3543 return WINED3D_OK;
3546 if(pShader == oldShader) {
3547 TRACE("App is setting the old pixel shader over, nothing to do\n");
3548 return WINED3D_OK;
3551 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3554 /* Rebuild the texture unit mapping if nvrc's are supported */
3555 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3556 IWineD3DDeviceImpl_FindTexUnitMap(This);
3559 return WINED3D_OK;
3562 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 if (NULL == ppShader) {
3566 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3567 return WINED3DERR_INVALIDCALL;
3570 *ppShader = This->stateBlock->pixelShader;
3571 if (NULL != *ppShader) {
3572 IWineD3DPixelShader_AddRef(*ppShader);
3574 TRACE("(%p) : returning %p\n", This, *ppShader);
3575 return WINED3D_OK;
3578 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3579 IWineD3DDevice *iface,
3580 UINT start,
3581 CONST BOOL *srcData,
3582 UINT count) {
3584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 int i, cnt = min(count, MAX_CONST_B - start);
3587 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3588 iface, srcData, start, count);
3590 if (srcData == NULL || cnt < 0)
3591 return WINED3DERR_INVALIDCALL;
3593 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3594 for (i = 0; i < cnt; i++)
3595 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3597 for (i = start; i < cnt + start; ++i) {
3598 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3599 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3602 return WINED3D_OK;
3605 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3606 IWineD3DDevice *iface,
3607 UINT start,
3608 BOOL *dstData,
3609 UINT count) {
3611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3612 int cnt = min(count, MAX_CONST_B - start);
3614 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3615 iface, dstData, start, count);
3617 if (dstData == NULL || cnt < 0)
3618 return WINED3DERR_INVALIDCALL;
3620 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3621 return WINED3D_OK;
3624 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3625 IWineD3DDevice *iface,
3626 UINT start,
3627 CONST int *srcData,
3628 UINT count) {
3630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3631 int i, cnt = min(count, MAX_CONST_I - start);
3633 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3634 iface, srcData, start, count);
3636 if (srcData == NULL || cnt < 0)
3637 return WINED3DERR_INVALIDCALL;
3639 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3640 for (i = 0; i < cnt; i++)
3641 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3642 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3644 for (i = start; i < cnt + start; ++i) {
3645 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3646 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3649 return WINED3D_OK;
3652 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3653 IWineD3DDevice *iface,
3654 UINT start,
3655 int *dstData,
3656 UINT count) {
3658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3659 int cnt = min(count, MAX_CONST_I - start);
3661 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3662 iface, dstData, start, count);
3664 if (dstData == NULL || cnt < 0)
3665 return WINED3DERR_INVALIDCALL;
3667 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3668 return WINED3D_OK;
3671 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3672 IWineD3DDevice *iface,
3673 UINT start,
3674 CONST float *srcData,
3675 UINT count) {
3677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3678 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3680 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3681 iface, srcData, start, count);
3683 if (srcData == NULL || cnt < 0)
3684 return WINED3DERR_INVALIDCALL;
3686 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3687 for (i = 0; i < cnt; i++)
3688 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3689 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3691 for (i = start; i < cnt + start; ++i) {
3692 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3693 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3694 ptr->idx = i;
3695 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3696 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3698 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3701 return WINED3D_OK;
3704 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3705 IWineD3DDevice *iface,
3706 UINT start,
3707 float *dstData,
3708 UINT count) {
3710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3711 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3713 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3714 iface, dstData, start, count);
3716 if (dstData == NULL || cnt < 0)
3717 return WINED3DERR_INVALIDCALL;
3719 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3720 return WINED3D_OK;
3723 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3724 static HRESULT
3725 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3726 char *dest_ptr, *dest_conv = NULL;
3727 unsigned int i;
3728 DWORD DestFVF = dest->fvf;
3729 WINED3DVIEWPORT vp;
3730 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3731 BOOL doClip;
3732 int numTextures;
3734 if (SrcFVF & WINED3DFVF_NORMAL) {
3735 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3738 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3739 ERR("Source has no position mask\n");
3740 return WINED3DERR_INVALIDCALL;
3743 /* We might access VBOs from this code, so hold the lock */
3744 ENTER_GL();
3746 if (dest->resource.allocatedMemory == NULL) {
3747 /* This may happen if we do direct locking into a vbo. Unlikely,
3748 * but theoretically possible(ddraw processvertices test)
3750 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3751 if(!dest->resource.allocatedMemory) {
3752 LEAVE_GL();
3753 ERR("Out of memory\n");
3754 return E_OUTOFMEMORY;
3756 if(dest->vbo) {
3757 void *src;
3758 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3759 checkGLcall("glBindBufferARB");
3760 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3761 if(src) {
3762 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3764 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3765 checkGLcall("glUnmapBufferARB");
3769 /* Get a pointer into the destination vbo(create one if none exists) and
3770 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3772 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3773 CreateVBO(dest);
3776 if(dest->vbo) {
3777 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3778 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3779 if(!dest_conv) {
3780 ERR("glMapBuffer failed\n");
3781 /* Continue without storing converted vertices */
3785 /* Should I clip?
3786 * a) WINED3DRS_CLIPPING is enabled
3787 * b) WINED3DVOP_CLIP is passed
3789 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3790 static BOOL warned = FALSE;
3792 * The clipping code is not quite correct. Some things need
3793 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3794 * so disable clipping for now.
3795 * (The graphics in Half-Life are broken, and my processvertices
3796 * test crashes with IDirect3DDevice3)
3797 doClip = TRUE;
3799 doClip = FALSE;
3800 if(!warned) {
3801 warned = TRUE;
3802 FIXME("Clipping is broken and disabled for now\n");
3804 } else doClip = FALSE;
3805 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3806 if(dest_conv) {
3807 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3810 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3811 WINED3DTS_VIEW,
3812 &view_mat);
3813 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3814 WINED3DTS_PROJECTION,
3815 &proj_mat);
3816 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3817 WINED3DTS_WORLDMATRIX(0),
3818 &world_mat);
3820 TRACE("View mat:\n");
3821 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); \
3822 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); \
3823 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); \
3824 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); \
3826 TRACE("Proj mat:\n");
3827 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); \
3828 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); \
3829 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); \
3830 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); \
3832 TRACE("World mat:\n");
3833 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); \
3834 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); \
3835 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); \
3836 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); \
3838 /* Get the viewport */
3839 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3840 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3841 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3843 multiply_matrix(&mat,&view_mat,&world_mat);
3844 multiply_matrix(&mat,&proj_mat,&mat);
3846 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3848 for (i = 0; i < dwCount; i+= 1) {
3849 unsigned int tex_index;
3851 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3852 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3853 /* The position first */
3854 float *p =
3855 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3856 float x, y, z, rhw;
3857 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3859 /* Multiplication with world, view and projection matrix */
3860 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);
3861 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);
3862 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);
3863 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);
3865 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3867 /* WARNING: The following things are taken from d3d7 and were not yet checked
3868 * against d3d8 or d3d9!
3871 /* Clipping conditions: From
3872 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3874 * A vertex is clipped if it does not match the following requirements
3875 * -rhw < x <= rhw
3876 * -rhw < y <= rhw
3877 * 0 < z <= rhw
3878 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3880 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3881 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3885 if( !doClip ||
3886 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3887 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3888 ( rhw > eps ) ) ) {
3890 /* "Normal" viewport transformation (not clipped)
3891 * 1) The values are divided by rhw
3892 * 2) The y axis is negative, so multiply it with -1
3893 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3894 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3895 * 4) Multiply x with Width/2 and add Width/2
3896 * 5) The same for the height
3897 * 6) Add the viewpoint X and Y to the 2D coordinates and
3898 * The minimum Z value to z
3899 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3901 * Well, basically it's simply a linear transformation into viewport
3902 * coordinates
3905 x /= rhw;
3906 y /= rhw;
3907 z /= rhw;
3909 y *= -1;
3911 x *= vp.Width / 2;
3912 y *= vp.Height / 2;
3913 z *= vp.MaxZ - vp.MinZ;
3915 x += vp.Width / 2 + vp.X;
3916 y += vp.Height / 2 + vp.Y;
3917 z += vp.MinZ;
3919 rhw = 1 / rhw;
3920 } else {
3921 /* That vertex got clipped
3922 * Contrary to OpenGL it is not dropped completely, it just
3923 * undergoes a different calculation.
3925 TRACE("Vertex got clipped\n");
3926 x += rhw;
3927 y += rhw;
3929 x /= 2;
3930 y /= 2;
3932 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3933 * outside of the main vertex buffer memory. That needs some more
3934 * investigation...
3938 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3941 ( (float *) dest_ptr)[0] = x;
3942 ( (float *) dest_ptr)[1] = y;
3943 ( (float *) dest_ptr)[2] = z;
3944 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3946 dest_ptr += 3 * sizeof(float);
3948 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3949 dest_ptr += sizeof(float);
3952 if(dest_conv) {
3953 float w = 1 / rhw;
3954 ( (float *) dest_conv)[0] = x * w;
3955 ( (float *) dest_conv)[1] = y * w;
3956 ( (float *) dest_conv)[2] = z * w;
3957 ( (float *) dest_conv)[3] = w;
3959 dest_conv += 3 * sizeof(float);
3961 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3962 dest_conv += sizeof(float);
3966 if (DestFVF & WINED3DFVF_PSIZE) {
3967 dest_ptr += sizeof(DWORD);
3968 if(dest_conv) dest_conv += sizeof(DWORD);
3970 if (DestFVF & WINED3DFVF_NORMAL) {
3971 float *normal =
3972 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3973 /* AFAIK this should go into the lighting information */
3974 FIXME("Didn't expect the destination to have a normal\n");
3975 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3976 if(dest_conv) {
3977 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3981 if (DestFVF & WINED3DFVF_DIFFUSE) {
3982 DWORD *color_d =
3983 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3984 if(!color_d) {
3985 static BOOL warned = FALSE;
3987 if(!warned) {
3988 ERR("No diffuse color in source, but destination has one\n");
3989 warned = TRUE;
3992 *( (DWORD *) dest_ptr) = 0xffffffff;
3993 dest_ptr += sizeof(DWORD);
3995 if(dest_conv) {
3996 *( (DWORD *) dest_conv) = 0xffffffff;
3997 dest_conv += sizeof(DWORD);
4000 else {
4001 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4002 if(dest_conv) {
4003 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4004 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4005 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4006 dest_conv += sizeof(DWORD);
4011 if (DestFVF & WINED3DFVF_SPECULAR) {
4012 /* What's the color value in the feedback buffer? */
4013 DWORD *color_s =
4014 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4015 if(!color_s) {
4016 static BOOL warned = FALSE;
4018 if(!warned) {
4019 ERR("No specular color in source, but destination has one\n");
4020 warned = TRUE;
4023 *( (DWORD *) dest_ptr) = 0xFF000000;
4024 dest_ptr += sizeof(DWORD);
4026 if(dest_conv) {
4027 *( (DWORD *) dest_conv) = 0xFF000000;
4028 dest_conv += sizeof(DWORD);
4031 else {
4032 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4033 if(dest_conv) {
4034 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4035 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4036 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4037 dest_conv += sizeof(DWORD);
4042 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4043 float *tex_coord =
4044 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4045 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4046 if(!tex_coord) {
4047 ERR("No source texture, but destination requests one\n");
4048 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4049 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4051 else {
4052 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4053 if(dest_conv) {
4054 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4060 if(dest_conv) {
4061 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4062 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4065 LEAVE_GL();
4067 return WINED3D_OK;
4069 #undef copy_and_next
4071 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4073 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4074 WineDirect3DVertexStridedData strided;
4075 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4077 if (!SrcImpl) {
4078 WARN("NULL source vertex buffer\n");
4079 return WINED3DERR_INVALIDCALL;
4081 /* We don't need the source vbo because this buffer is only used as
4082 * a source for ProcessVertices. Avoid wasting resources by converting the
4083 * buffer and loading the VBO
4085 if(SrcImpl->vbo) {
4086 TRACE("Releasing the source vbo, it won't be needed\n");
4088 if(!SrcImpl->resource.allocatedMemory) {
4089 /* Rescue the data from the buffer */
4090 void *src;
4091 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4092 if(!SrcImpl->resource.allocatedMemory) {
4093 ERR("Out of memory\n");
4094 return E_OUTOFMEMORY;
4097 ENTER_GL();
4098 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4099 checkGLcall("glBindBufferARB");
4101 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4102 if(src) {
4103 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4106 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4107 checkGLcall("glUnmapBufferARB");
4108 } else {
4109 ENTER_GL();
4112 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4113 checkGLcall("glBindBufferARB");
4114 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4115 checkGLcall("glDeleteBuffersARB");
4116 LEAVE_GL();
4118 SrcImpl->vbo = 0;
4121 memset(&strided, 0, sizeof(strided));
4122 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4124 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4127 /*****
4128 * Get / Set Texture Stage States
4129 * TODO: Verify against dx9 definitions
4130 *****/
4131 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4135 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4137 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4139 /* Reject invalid texture units */
4140 if (Stage >= GL_LIMITS(texture_stages)) {
4141 TRACE("Attempt to access invalid texture rejected\n");
4142 return WINED3DERR_INVALIDCALL;
4145 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4146 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4147 This->updateStateBlock->textureState[Stage][Type] = Value;
4149 if (This->isRecordingState) {
4150 TRACE("Recording... not performing anything\n");
4151 return WINED3D_OK;
4154 /* Checked after the assignments to allow proper stateblock recording */
4155 if(oldValue == Value) {
4156 TRACE("App is setting the old value over, nothing to do\n");
4157 return WINED3D_OK;
4160 if(Stage > This->stateBlock->lowest_disabled_stage &&
4161 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4162 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4163 * Changes in other states are important on disabled stages too
4165 return WINED3D_OK;
4168 if(Type == WINED3DTSS_COLOROP) {
4169 int i;
4171 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4172 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4173 * they have to be disabled
4175 * The current stage is dirtified below.
4177 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4178 TRACE("Additionally dirtifying stage %d\n", i);
4179 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4181 This->stateBlock->lowest_disabled_stage = Stage;
4182 TRACE("New lowest disabled: %d\n", Stage);
4183 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4184 /* Previously disabled stage enabled. Stages above it may need enabling
4185 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4186 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4188 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4191 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4192 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4193 break;
4195 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4198 This->stateBlock->lowest_disabled_stage = i;
4199 TRACE("New lowest disabled: %d\n", i);
4201 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4202 /* TODO: Built a stage -> texture unit mapping for register combiners */
4206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4208 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4209 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4210 * will call FindTexUnitMap too.
4212 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4213 IWineD3DDeviceImpl_FindTexUnitMap(This);
4215 return WINED3D_OK;
4218 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4220 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4221 *pValue = This->updateStateBlock->textureState[Stage][Type];
4222 return WINED3D_OK;
4225 /*****
4226 * Get / Set Texture
4227 *****/
4228 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4231 IWineD3DBaseTexture *oldTexture;
4233 oldTexture = This->updateStateBlock->textures[Stage];
4234 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4236 #if 0 /* TODO: check so vertex textures */
4237 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4238 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4239 return WINED3D_OK;
4241 #endif
4243 /* Reject invalid texture units */
4244 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4245 WARN("Attempt to access invalid texture rejected\n");
4246 return WINED3DERR_INVALIDCALL;
4249 if(pTexture != NULL) {
4250 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4252 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4253 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4254 return WINED3DERR_INVALIDCALL;
4256 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4259 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4260 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4262 This->updateStateBlock->set.textures[Stage] = TRUE;
4263 This->updateStateBlock->changed.textures[Stage] = TRUE;
4264 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4265 This->updateStateBlock->textures[Stage] = pTexture;
4267 /* Handle recording of state blocks */
4268 if (This->isRecordingState) {
4269 TRACE("Recording... not performing anything\n");
4270 return WINED3D_OK;
4273 if(oldTexture == pTexture) {
4274 TRACE("App is setting the same texture again, nothing to do\n");
4275 return WINED3D_OK;
4278 /** NOTE: MSDN says that setTexture increases the reference count,
4279 * and the the application nust set the texture back to null (or have a leaky application),
4280 * This means we should pass the refcount up to the parent
4281 *******************************/
4282 if (NULL != This->updateStateBlock->textures[Stage]) {
4283 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4284 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4286 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4287 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4288 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4289 * so the COLOROP and ALPHAOP have to be dirtified.
4291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4294 if(bindCount == 1) {
4295 new->baseTexture.sampler = Stage;
4297 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4301 if (NULL != oldTexture) {
4302 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4303 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4305 IWineD3DBaseTexture_Release(oldTexture);
4306 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4311 if(bindCount && old->baseTexture.sampler == Stage) {
4312 int i;
4313 /* Have to do a search for the other sampler(s) where the texture is bound to
4314 * Shouldn't happen as long as apps bind a texture only to one stage
4316 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4317 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4318 if(This->updateStateBlock->textures[i] == oldTexture) {
4319 old->baseTexture.sampler = i;
4320 break;
4326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4328 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4329 * pixel shader is used
4331 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4332 IWineD3DDeviceImpl_FindTexUnitMap(This);
4335 return WINED3D_OK;
4338 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4340 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4342 /* Reject invalid texture units */
4343 if (Stage >= GL_LIMITS(sampler_stages)) {
4344 TRACE("Attempt to access invalid texture rejected\n");
4345 return WINED3DERR_INVALIDCALL;
4347 *ppTexture=This->stateBlock->textures[Stage];
4348 if (*ppTexture)
4349 IWineD3DBaseTexture_AddRef(*ppTexture);
4351 return WINED3D_OK;
4354 /*****
4355 * Get Back Buffer
4356 *****/
4357 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4358 IWineD3DSurface **ppBackBuffer) {
4359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4360 IWineD3DSwapChain *swapChain;
4361 HRESULT hr;
4363 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4365 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4366 if (hr == WINED3D_OK) {
4367 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4368 IWineD3DSwapChain_Release(swapChain);
4369 } else {
4370 *ppBackBuffer = NULL;
4372 return hr;
4375 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4377 WARN("(%p) : stub, calling idirect3d for now\n", This);
4378 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4381 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 IWineD3DSwapChain *swapChain;
4384 HRESULT hr;
4386 if(iSwapChain > 0) {
4387 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4388 if (hr == WINED3D_OK) {
4389 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4390 IWineD3DSwapChain_Release(swapChain);
4391 } else {
4392 FIXME("(%p) Error getting display mode\n", This);
4394 } else {
4395 /* Don't read the real display mode,
4396 but return the stored mode instead. X11 can't change the color
4397 depth, and some apps are pretty angry if they SetDisplayMode from
4398 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4400 Also don't relay to the swapchain because with ddraw it's possible
4401 that there isn't a swapchain at all */
4402 pMode->Width = This->ddraw_width;
4403 pMode->Height = This->ddraw_height;
4404 pMode->Format = This->ddraw_format;
4405 pMode->RefreshRate = 0;
4406 hr = WINED3D_OK;
4409 return hr;
4412 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4414 TRACE("(%p)->(%p)\n", This, hWnd);
4416 This->ddraw_window = hWnd;
4417 return WINED3D_OK;
4420 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4422 TRACE("(%p)->(%p)\n", This, hWnd);
4424 *hWnd = This->ddraw_window;
4425 return WINED3D_OK;
4428 /*****
4429 * Stateblock related functions
4430 *****/
4432 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4434 IWineD3DStateBlockImpl *object;
4435 HRESULT temp_result;
4437 TRACE("(%p)\n", This);
4439 if (This->isRecordingState) {
4440 return WINED3DERR_INVALIDCALL;
4443 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4444 if (NULL == object ) {
4445 FIXME("(%p)Error allocating memory for stateblock\n", This);
4446 return E_OUTOFMEMORY;
4448 TRACE("(%p) created object %p\n", This, object);
4449 object->wineD3DDevice= This;
4450 /** FIXME: object->parent = parent; **/
4451 object->parent = NULL;
4452 object->blockType = WINED3DSBT_ALL;
4453 object->ref = 1;
4454 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4456 temp_result = allocate_shader_constants(object);
4457 if (WINED3D_OK != temp_result)
4458 return temp_result;
4460 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4461 This->updateStateBlock = object;
4462 This->isRecordingState = TRUE;
4464 TRACE("(%p) recording stateblock %p\n",This , object);
4465 return WINED3D_OK;
4468 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4471 if (!This->isRecordingState) {
4472 FIXME("(%p) not recording! returning error\n", This);
4473 *ppStateBlock = NULL;
4474 return WINED3DERR_INVALIDCALL;
4477 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4478 This->isRecordingState = FALSE;
4479 This->updateStateBlock = This->stateBlock;
4480 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4481 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4482 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4483 return WINED3D_OK;
4486 /*****
4487 * Scene related functions
4488 *****/
4489 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4490 /* At the moment we have no need for any functionality at the beginning
4491 of a scene */
4492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4493 TRACE("(%p) : stub\n", This);
4494 return WINED3D_OK;
4497 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4499 TRACE("(%p)\n", This);
4500 ENTER_GL();
4501 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4502 glFlush();
4503 checkGLcall("glFlush");
4505 TRACE("End Scene\n");
4506 /* If we're using FBOs this isn't needed */
4507 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4509 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4510 IUnknown *targetContainer = NULL;
4511 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4512 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4513 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4514 /** always dirtify for now. we must find a better way to see that surface have been modified
4515 (Modifications should will only occur via draw-primitive, but we do need better locking
4516 switching to render-to-texture should remove the overhead though.
4518 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4519 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4520 IWineD3DSurface_PreLoad(This->render_targets[0]);
4521 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4522 IUnknown_Release(targetContainer);
4525 This->sceneEnded = TRUE;
4526 LEAVE_GL();
4527 return WINED3D_OK;
4530 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4531 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4532 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4534 IWineD3DSwapChain *swapChain = NULL;
4535 int i;
4536 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4538 TRACE("(%p) Presenting the frame\n", This);
4540 for(i = 0 ; i < swapchains ; i ++) {
4542 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4543 TRACE("presentinng chain %d, %p\n", i, swapChain);
4544 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4545 IWineD3DSwapChain_Release(swapChain);
4548 return WINED3D_OK;
4551 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4552 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4555 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4556 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4557 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4558 GLbitfield glMask = 0;
4559 GLboolean old_ztest;
4560 GLfloat old_z_clear_value;
4561 GLint old_stencil_clear_value;
4562 GLfloat old_color_clear_value[4];
4563 unsigned int i;
4564 CONST WINED3DRECT* curRect;
4566 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4567 Count, pRects, Flags, Z, Stencil);
4569 ENTER_GL();
4571 glEnable(GL_SCISSOR_TEST);
4572 checkGLcall("glEnable GL_SCISSOR_TEST");
4574 if (Count > 0 && pRects) {
4575 curRect = pRects;
4576 } else {
4577 curRect = NULL;
4580 /* Only set the values up once, as they are not changing */
4581 if (Flags & WINED3DCLEAR_STENCIL) {
4582 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4583 glClearStencil(Stencil);
4584 checkGLcall("glClearStencil");
4585 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4586 glStencilMask(0xFFFFFFFF);
4589 if (Flags & WINED3DCLEAR_ZBUFFER) {
4590 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4591 glDepthMask(GL_TRUE);
4592 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4593 glClearDepth(Z);
4594 checkGLcall("glClearDepth");
4595 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4598 if (Flags & WINED3DCLEAR_TARGET) {
4599 TRACE("Clearing screen with glClear to color %x\n", Color);
4600 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4601 glClearColor(D3DCOLOR_R(Color),
4602 D3DCOLOR_G(Color),
4603 D3DCOLOR_B(Color),
4604 D3DCOLOR_A(Color));
4605 checkGLcall("glClearColor");
4607 /* Clear ALL colors! */
4608 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4609 glMask = glMask | GL_COLOR_BUFFER_BIT;
4612 /* Now process each rect in turn */
4613 for (i = 0; i < Count || i == 0; i++) {
4615 if (curRect) {
4616 /* Note gl uses lower left, width/height */
4617 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4618 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4619 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4620 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4621 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4622 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4623 checkGLcall("glScissor");
4624 } else {
4625 glScissor(This->stateBlock->viewport.X,
4626 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4627 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4628 This->stateBlock->viewport.Width,
4629 This->stateBlock->viewport.Height);
4630 checkGLcall("glScissor");
4633 /* Clear the selected rectangle (or full screen) */
4634 glClear(glMask);
4635 checkGLcall("glClear");
4637 /* Step to the next rectangle */
4638 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4641 /* Restore the old values (why..?) */
4642 if (Flags & WINED3DCLEAR_STENCIL) {
4643 glClearStencil(old_stencil_clear_value);
4644 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4646 if (Flags & WINED3DCLEAR_ZBUFFER) {
4647 glDepthMask(old_ztest);
4648 glClearDepth(old_z_clear_value);
4650 if (Flags & WINED3DCLEAR_TARGET) {
4651 glClearColor(old_color_clear_value[0],
4652 old_color_clear_value[1],
4653 old_color_clear_value[2],
4654 old_color_clear_value[3]);
4655 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4656 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4657 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4658 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4661 glDisable(GL_SCISSOR_TEST);
4662 checkGLcall("glDisable");
4663 LEAVE_GL();
4665 return WINED3D_OK;
4668 /*****
4669 * Drawing functions
4670 *****/
4671 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4672 UINT PrimitiveCount) {
4674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 This->stateBlock->streamIsUP = FALSE;
4677 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4678 debug_d3dprimitivetype(PrimitiveType),
4679 StartVertex, PrimitiveCount);
4681 if(StartVertex - This->stateBlock->baseVertexIndex < 0) ERR("Drawing negative\n");
4682 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4683 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex - This->stateBlock->baseVertexIndex, 0/* NumVertices */, -1 /* indxStart */,
4684 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4685 return WINED3D_OK;
4688 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4689 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4690 WINED3DPRIMITIVETYPE PrimitiveType,
4691 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4694 UINT idxStride = 2;
4695 IWineD3DIndexBuffer *pIB;
4696 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4698 pIB = This->stateBlock->pIndexData;
4699 This->stateBlock->streamIsUP = FALSE;
4701 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4702 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4703 minIndex, NumVertices, startIndex, primCount);
4705 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4706 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4707 idxStride = 2;
4708 } else {
4709 idxStride = 4;
4712 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4713 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4715 return WINED3D_OK;
4718 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4719 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4720 UINT VertexStreamZeroStride) {
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4723 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4724 debug_d3dprimitivetype(PrimitiveType),
4725 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4727 /* release the stream source */
4728 if (This->stateBlock->streamSource[0] != NULL) {
4729 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4732 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4733 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4734 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4735 This->stateBlock->streamIsUP = TRUE;
4737 drawPrimitive(iface, PrimitiveType, PrimitiveCount, -This->stateBlock->baseVertexIndex /* start vertex */, 0 /* NumVertices */,
4738 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4740 /* MSDN specifies stream zero settings must be set to NULL */
4741 This->stateBlock->streamStride[0] = 0;
4742 This->stateBlock->streamSource[0] = NULL;
4744 /*stream zero settings set to null at end, as per the msdn */
4745 return WINED3D_OK;
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) {
4753 int idxStride;
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) {
4762 idxStride = 2;
4763 } else {
4764 idxStride = 4;
4767 /* release the stream and index data */
4768 if (This->stateBlock->streamSource[0] != NULL) {
4769 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4771 if (This->stateBlock->pIndexData) {
4772 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
4775 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4776 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4777 This->stateBlock->streamIsUP = TRUE;
4778 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4780 /* Mark the state dirty until we have nicer tracking */
4781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4782 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4783 This->stateBlock->baseVertexIndex = 0;
4785 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4787 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4788 This->stateBlock->streamSource[0] = NULL;
4789 This->stateBlock->streamStride[0] = 0;
4790 This->stateBlock->pIndexData = NULL;
4792 return WINED3D_OK;
4795 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4798 /* Mark the state dirty until we have nicer tracking
4799 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4800 * that value.
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4803 This->stateBlock->baseVertexIndex = 0;
4804 This->up_strided = DrawPrimStrideData;
4805 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4806 This->up_strided = NULL;
4807 return WINED3D_OK;
4809 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4810 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 HRESULT hr = WINED3D_OK;
4813 WINED3DRESOURCETYPE sourceType;
4814 WINED3DRESOURCETYPE destinationType;
4815 int i ,levels;
4817 /* TODO: think about moving the code into IWineD3DBaseTexture */
4819 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4821 /* verify that the source and destination textures aren't NULL */
4822 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4823 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4824 This, pSourceTexture, pDestinationTexture);
4825 hr = WINED3DERR_INVALIDCALL;
4828 if (pSourceTexture == pDestinationTexture) {
4829 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4830 This, pSourceTexture, pDestinationTexture);
4831 hr = WINED3DERR_INVALIDCALL;
4833 /* Verify that the source and destination textures are the same type */
4834 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4835 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4837 if (sourceType != destinationType) {
4838 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4839 This);
4840 hr = WINED3DERR_INVALIDCALL;
4843 /* check that both textures have the identical numbers of levels */
4844 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4845 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4846 hr = WINED3DERR_INVALIDCALL;
4849 if (WINED3D_OK == hr) {
4851 /* Make sure that the destination texture is loaded */
4852 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4854 /* Update every surface level of the texture */
4855 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4857 switch (sourceType) {
4858 case WINED3DRTYPE_TEXTURE:
4860 IWineD3DSurface *srcSurface;
4861 IWineD3DSurface *destSurface;
4863 for (i = 0 ; i < levels ; ++i) {
4864 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4865 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4866 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4867 IWineD3DSurface_Release(srcSurface);
4868 IWineD3DSurface_Release(destSurface);
4869 if (WINED3D_OK != hr) {
4870 WARN("(%p) : Call to update surface failed\n", This);
4871 return hr;
4875 break;
4876 case WINED3DRTYPE_CUBETEXTURE:
4878 IWineD3DSurface *srcSurface;
4879 IWineD3DSurface *destSurface;
4880 WINED3DCUBEMAP_FACES faceType;
4882 for (i = 0 ; i < levels ; ++i) {
4883 /* Update each cube face */
4884 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4885 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4886 if (WINED3D_OK != hr) {
4887 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4888 } else {
4889 TRACE("Got srcSurface %p\n", srcSurface);
4891 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4892 if (WINED3D_OK != hr) {
4893 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4894 } else {
4895 TRACE("Got desrSurface %p\n", destSurface);
4897 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4898 IWineD3DSurface_Release(srcSurface);
4899 IWineD3DSurface_Release(destSurface);
4900 if (WINED3D_OK != hr) {
4901 WARN("(%p) : Call to update surface failed\n", This);
4902 return hr;
4907 break;
4908 #if 0 /* TODO: Add support for volume textures */
4909 case WINED3DRTYPE_VOLUMETEXTURE:
4911 IWineD3DVolume srcVolume = NULL;
4912 IWineD3DSurface destVolume = NULL;
4914 for (i = 0 ; i < levels ; ++i) {
4915 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4916 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4917 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4918 IWineD3DVolume_Release(srcSurface);
4919 IWineD3DVolume_Release(destSurface);
4920 if (WINED3D_OK != hr) {
4921 WARN("(%p) : Call to update volume failed\n", This);
4922 return hr;
4926 break;
4927 #endif
4928 default:
4929 FIXME("(%p) : Unsupported source and destination type\n", This);
4930 hr = WINED3DERR_INVALIDCALL;
4934 return hr;
4937 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
4938 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
4939 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4942 TRACE("(%p) : stub\n", This);
4943 return WINED3D_OK;
4945 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
4948 * NOTE It may be best to move the code into surface to occomplish this
4949 ****************************************/
4951 WINED3DSURFACE_DESC surfaceDesc;
4952 unsigned int surfaceWidth, surfaceHeight;
4953 glDescriptor *targetGlDescription = NULL;
4954 glDescriptor *surfaceGlDescription = NULL;
4955 IWineD3DSwapChainImpl *container = NULL;
4957 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
4958 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
4959 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
4961 surfaceDesc.Width = &surfaceWidth;
4962 surfaceDesc.Height = &surfaceHeight;
4963 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
4964 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
4966 /* Ok, I may need to setup some kind of active swapchain reference on the device */
4967 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
4968 ENTER_GL();
4969 /* TODO: opengl Context switching for swapchains etc... */
4970 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
4971 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
4972 glReadBuffer(GL_BACK);
4973 vcheckGLcall("glReadBuffer(GL_BACK)");
4974 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
4975 glReadBuffer(GL_FRONT);
4976 vcheckGLcall("glReadBuffer(GL_FRONT)");
4977 } else if (pRenderTarget == This->depthStencilBuffer) {
4978 FIXME("Reading of depthstencil not yet supported\n");
4981 glReadPixels(0,
4983 surfaceWidth,
4984 surfaceHeight,
4985 surfaceGlDescription->glFormat,
4986 surfaceGlDescription->glType,
4987 (void *)IWineD3DSurface_GetData(pSurface));
4988 vcheckGLcall("glReadPixels(...)");
4989 if(NULL != container ){
4990 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
4992 } else {
4993 IWineD3DBaseTexture *container;
4994 GLenum textureDimensions = GL_TEXTURE_2D;
4996 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
4997 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
4998 IWineD3DBaseTexture_Release(container);
5000 /* TODO: 2D -> Cube surface coppies etc.. */
5001 if (surfaceGlDescription->target != textureDimensions) {
5002 FIXME("(%p) : Texture dimension mismatch\n", This);
5004 glEnable(textureDimensions);
5005 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5006 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5007 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5008 vcheckGLcall("glBindTexture");
5009 glGetTexImage(surfaceGlDescription->target,
5010 surfaceGlDescription->level,
5011 surfaceGlDescription->glFormat,
5012 surfaceGlDescription->glType,
5013 (void *)IWineD3DSurface_GetData(pSurface));
5014 glDisable(textureDimensions);
5015 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5018 LEAVE_GL();
5019 return WINED3D_OK;
5022 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5023 IWineD3DSwapChain *swapChain;
5024 HRESULT hr;
5025 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5026 if(hr == WINED3D_OK) {
5027 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5028 IWineD3DSwapChain_Release(swapChain);
5030 return hr;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5035 /* return a sensible default */
5036 *pNumPasses = 1;
5037 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5038 FIXME("(%p) : stub\n", This);
5039 return WINED3D_OK;
5042 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5044 int j;
5045 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5046 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5047 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5048 return WINED3DERR_INVALIDCALL;
5050 for (j = 0; j < 256; ++j) {
5051 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5052 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5053 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5054 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5056 TRACE("(%p) : returning\n", This);
5057 return WINED3D_OK;
5060 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5062 int j;
5063 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5064 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5065 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5066 return WINED3DERR_INVALIDCALL;
5068 for (j = 0; j < 256; ++j) {
5069 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5070 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5071 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5072 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5074 TRACE("(%p) : returning\n", This);
5075 return WINED3D_OK;
5078 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5081 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5082 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5083 return WINED3DERR_INVALIDCALL;
5085 /*TODO: stateblocks */
5086 This->currentPalette = PaletteNumber;
5087 TRACE("(%p) : returning\n", This);
5088 return WINED3D_OK;
5091 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5093 if (PaletteNumber == NULL) {
5094 WARN("(%p) : returning Invalid Call\n", This);
5095 return WINED3DERR_INVALIDCALL;
5097 /*TODO: stateblocks */
5098 *PaletteNumber = This->currentPalette;
5099 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5100 return WINED3D_OK;
5103 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5105 static BOOL showFixmes = TRUE;
5106 if (showFixmes) {
5107 FIXME("(%p) : stub\n", This);
5108 showFixmes = FALSE;
5111 This->softwareVertexProcessing = bSoftware;
5112 return WINED3D_OK;
5116 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5118 static BOOL showFixmes = TRUE;
5119 if (showFixmes) {
5120 FIXME("(%p) : stub\n", This);
5121 showFixmes = FALSE;
5123 return This->softwareVertexProcessing;
5127 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 IWineD3DSwapChain *swapChain;
5130 HRESULT hr;
5132 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5134 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5135 if(hr == WINED3D_OK){
5136 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5137 IWineD3DSwapChain_Release(swapChain);
5138 }else{
5139 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5141 return hr;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5147 static BOOL showfixmes = TRUE;
5148 if(nSegments != 0.0f) {
5149 if( showfixmes) {
5150 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5151 showfixmes = FALSE;
5154 return WINED3D_OK;
5157 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5159 static BOOL showfixmes = TRUE;
5160 if( showfixmes) {
5161 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5162 showfixmes = FALSE;
5164 return 0.0f;
5167 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5169 /** TODO: remove casts to IWineD3DSurfaceImpl
5170 * NOTE: move code to surface to accomplish this
5171 ****************************************/
5172 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5173 int srcWidth, srcHeight;
5174 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5175 WINED3DFORMAT destFormat, srcFormat;
5176 UINT destSize;
5177 int destLeft, destTop;
5178 WINED3DPOOL srcPool, destPool;
5179 int offset = 0;
5180 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5181 glDescriptor *glDescription = NULL;
5182 GLenum textureDimensions = GL_TEXTURE_2D;
5183 IWineD3DBaseTexture *baseTexture;
5185 WINED3DSURFACE_DESC winedesc;
5187 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5188 memset(&winedesc, 0, sizeof(winedesc));
5189 winedesc.Width = &srcSurfaceWidth;
5190 winedesc.Height = &srcSurfaceHeight;
5191 winedesc.Pool = &srcPool;
5192 winedesc.Format = &srcFormat;
5194 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5196 winedesc.Width = &destSurfaceWidth;
5197 winedesc.Height = &destSurfaceHeight;
5198 winedesc.Pool = &destPool;
5199 winedesc.Format = &destFormat;
5200 winedesc.Size = &destSize;
5202 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5204 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5205 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5206 return WINED3DERR_INVALIDCALL;
5209 if (destFormat == WINED3DFMT_UNKNOWN) {
5210 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5211 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5213 /* Get the update surface description */
5214 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5217 /* Make sure the surface is loaded and up to date */
5218 IWineD3DSurface_PreLoad(pDestinationSurface);
5220 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5222 ENTER_GL();
5224 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5225 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5226 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5227 destLeft = pDestPoint ? pDestPoint->x : 0;
5228 destTop = pDestPoint ? pDestPoint->y : 0;
5231 /* This function doesn't support compressed textures
5232 the pitch is just bytesPerPixel * width */
5233 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5234 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5235 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5236 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5238 /* TODO DXT formats */
5240 if(pSourceRect != NULL && pSourceRect->top != 0){
5241 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5243 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5244 ,This
5245 ,glDescription->level
5246 ,destLeft
5247 ,destTop
5248 ,srcWidth
5249 ,srcHeight
5250 ,glDescription->glFormat
5251 ,glDescription->glType
5252 ,IWineD3DSurface_GetData(pSourceSurface)
5255 /* Sanity check */
5256 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5258 /* need to lock the surface to get the data */
5259 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5262 /* TODO: Cube and volume support */
5263 if(rowoffset != 0){
5264 /* not a whole row so we have to do it a line at a time */
5265 int j;
5267 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5268 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5270 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5272 glTexSubImage2D(glDescription->target
5273 ,glDescription->level
5274 ,destLeft
5276 ,srcWidth
5278 ,glDescription->glFormat
5279 ,glDescription->glType
5280 ,data /* could be quicker using */
5282 data += rowoffset;
5285 } else { /* Full width, so just write out the whole texture */
5287 if (WINED3DFMT_DXT1 == destFormat ||
5288 WINED3DFMT_DXT2 == destFormat ||
5289 WINED3DFMT_DXT3 == destFormat ||
5290 WINED3DFMT_DXT4 == destFormat ||
5291 WINED3DFMT_DXT5 == destFormat) {
5292 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5293 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5294 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5295 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5296 } if (destFormat != srcFormat) {
5297 FIXME("Updating mixed format compressed texture is not curretly support\n");
5298 } else {
5299 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5300 glDescription->level,
5301 glDescription->glFormatInternal,
5302 srcWidth,
5303 srcHeight,
5305 destSize,
5306 IWineD3DSurface_GetData(pSourceSurface));
5308 } else {
5309 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5313 } else {
5314 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5316 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5317 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5318 data returned by GetData non-power2 width/height with hardware non-power2
5319 pow2Width/height are set to surface width height, repacking isn't needed so it
5320 doesn't matter which function gets called. */
5321 glTexSubImage2D(glDescription->target
5322 ,glDescription->level
5323 ,destLeft
5324 ,destTop
5325 ,srcWidth
5326 ,srcHeight
5327 ,glDescription->glFormat
5328 ,glDescription->glType
5329 ,IWineD3DSurface_GetData(pSourceSurface)
5331 } else {
5333 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5334 glTexSubImage2D(glDescription->target
5335 ,glDescription->level
5336 ,destLeft
5337 ,destTop
5338 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5339 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5340 ,glDescription->glFormat
5341 ,glDescription->glType
5342 ,IWineD3DSurface_GetData(pSourceSurface)
5348 checkGLcall("glTexSubImage2D");
5349 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5351 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5352 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5353 * surface bigger than it needs to be hmm.. */
5354 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5355 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5356 IWineD3DBaseTexture_Release(baseTexture);
5359 glDisable(textureDimensions); /* This needs to be managed better.... */
5360 LEAVE_GL();
5362 return WINED3D_OK;
5365 /* Implementation details at http://developer.nvidia.com/attach/6494
5367 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5368 hmm.. no longer supported use
5369 OpenGL evaluators or tessellate surfaces within your application.
5372 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5373 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5375 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5376 FIXME("(%p) : Stub\n", This);
5377 return WINED3D_OK;
5381 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5382 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5384 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5385 FIXME("(%p) : Stub\n", This);
5386 return WINED3D_OK;
5389 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5391 TRACE("(%p) Handle(%d)\n", This, Handle);
5392 FIXME("(%p) : Stub\n", This);
5393 return WINED3D_OK;
5396 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5398 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5399 DDBLTFX BltFx;
5400 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5402 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5403 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5404 return WINED3DERR_INVALIDCALL;
5407 /* Just forward this to the DirectDraw blitting engine */
5408 memset(&BltFx, 0, sizeof(BltFx));
5409 BltFx.dwSize = sizeof(BltFx);
5410 BltFx.u5.dwFillColor = color;
5411 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5414 /* rendertarget and deptth stencil functions */
5415 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5418 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5419 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5420 return WINED3DERR_INVALIDCALL;
5423 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5424 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5425 /* Note inc ref on returned surface */
5426 if(*ppRenderTarget != NULL)
5427 IWineD3DSurface_AddRef(*ppRenderTarget);
5428 return WINED3D_OK;
5431 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5433 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5434 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5435 IWineD3DSwapChainImpl *Swapchain;
5436 HRESULT hr;
5438 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5440 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5441 if(hr != WINED3D_OK) {
5442 ERR("Can't get the swapchain\n");
5443 return hr;
5446 /* Make sure to release the swapchain */
5447 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5449 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5450 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5451 return WINED3DERR_INVALIDCALL;
5453 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5454 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5455 return WINED3DERR_INVALIDCALL;
5458 if(Swapchain->frontBuffer != Front) {
5459 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5461 if(Swapchain->frontBuffer)
5462 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5463 Swapchain->frontBuffer = Front;
5465 if(Swapchain->frontBuffer) {
5466 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5470 if(Back && !Swapchain->backBuffer) {
5471 /* We need memory for the back buffer array - only one back buffer this way */
5472 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5473 if(!Swapchain->backBuffer) {
5474 ERR("Out of memory\n");
5475 return E_OUTOFMEMORY;
5479 if(Swapchain->backBuffer[0] != Back) {
5480 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5481 ENTER_GL();
5482 if(!Swapchain->backBuffer[0]) {
5483 /* GL was told to draw to the front buffer at creation,
5484 * undo that
5486 glDrawBuffer(GL_BACK);
5487 checkGLcall("glDrawBuffer(GL_BACK)");
5488 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5489 Swapchain->presentParms.BackBufferCount = 1;
5490 } else if (!Back) {
5491 /* That makes problems - disable for now */
5492 /* glDrawBuffer(GL_FRONT); */
5493 checkGLcall("glDrawBuffer(GL_FRONT)");
5494 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5495 Swapchain->presentParms.BackBufferCount = 0;
5497 LEAVE_GL();
5499 if(Swapchain->backBuffer[0])
5500 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5501 Swapchain->backBuffer[0] = Back;
5503 if(Swapchain->backBuffer[0]) {
5504 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5505 } else {
5506 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5511 return WINED3D_OK;
5514 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5516 *ppZStencilSurface = This->depthStencilBuffer;
5517 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5519 if(*ppZStencilSurface != NULL) {
5520 /* Note inc ref on returned surface */
5521 IWineD3DSurface_AddRef(*ppZStencilSurface);
5523 return WINED3D_OK;
5526 static void bind_fbo(IWineD3DDevice *iface) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5529 if (!This->fbo) {
5530 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5531 checkGLcall("glGenFramebuffersEXT()");
5533 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5534 checkGLcall("glBindFramebuffer()");
5537 /* TODO: Handle stencil attachments */
5538 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5540 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5542 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5544 bind_fbo(iface);
5546 if (depth_stencil_impl) {
5547 GLenum texttarget, target;
5548 GLint old_binding = 0;
5550 IWineD3DSurface_PreLoad(depth_stencil);
5551 texttarget = depth_stencil_impl->glDescription.target;
5552 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5554 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5555 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5556 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5557 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5558 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5559 glBindTexture(target, old_binding);
5561 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5562 checkGLcall("glFramebufferTexture2DEXT()");
5563 } else {
5564 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5565 checkGLcall("glFramebufferTexture2DEXT()");
5568 if (!This->render_offscreen) {
5569 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5570 checkGLcall("glBindFramebuffer()");
5574 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5576 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5578 if (idx >= GL_LIMITS(buffers)) {
5579 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5582 bind_fbo(iface);
5584 if (rtimpl) {
5585 GLenum texttarget, target;
5586 GLint old_binding = 0;
5588 IWineD3DSurface_PreLoad(render_target);
5589 texttarget = rtimpl->glDescription.target;
5590 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5592 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5593 glBindTexture(target, rtimpl->glDescription.textureName);
5594 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5595 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5596 glBindTexture(target, old_binding);
5598 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5599 checkGLcall("glFramebufferTexture2DEXT()");
5601 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5602 } else {
5603 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5604 checkGLcall("glFramebufferTexture2DEXT()");
5606 This->draw_buffers[idx] = GL_NONE;
5609 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5610 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5611 checkGLcall("glDrawBuffers()");
5614 if (!This->render_offscreen) {
5615 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5616 checkGLcall("glBindFramebuffer()");
5620 /* internal static helper functions */
5621 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5622 IWineD3DSurface *RenderSurface);
5624 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5626 HRESULT hr = WINED3D_OK;
5627 WINED3DVIEWPORT viewport;
5629 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5631 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5632 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5633 return WINED3DERR_INVALIDCALL;
5636 /* MSDN says that null disables the render target
5637 but a device must always be associated with a render target
5638 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5640 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5641 for more details
5643 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5644 FIXME("Trying to set render target 0 to NULL\n");
5645 return WINED3DERR_INVALIDCALL;
5647 /* TODO: replace Impl* usage with interface usage */
5648 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5649 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);
5650 return WINED3DERR_INVALIDCALL;
5652 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5653 * builds, but I think wine counts as a 'debug' build for now.
5654 ******************************/
5655 /* If we are trying to set what we already have, don't bother */
5656 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5657 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5658 } else {
5659 /* Otherwise, set the render target up */
5661 if (!This->sceneEnded) {
5662 IWineD3DDevice_EndScene(iface);
5664 TRACE("clearing renderer\n");
5665 /* IWineD3DDeviceImpl_CleanRender(iface); */
5666 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5667 depending on the renter target implementation being used.
5668 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5669 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5670 stencil buffer and incure an extra memory overhead */
5671 if (RenderTargetIndex == 0) {
5672 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5673 } else {
5674 hr = WINED3D_OK;
5677 /* Replace the render target */
5678 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5679 This->render_targets[RenderTargetIndex] = pRenderTarget;
5680 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5682 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5683 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5687 if (SUCCEEDED(hr)) {
5688 /* Finally, reset the viewport as the MSDN states. */
5689 /* TODO: Replace impl usage */
5690 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5691 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5692 viewport.X = 0;
5693 viewport.Y = 0;
5694 viewport.MaxZ = 1.0f;
5695 viewport.MinZ = 0.0f;
5696 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5697 } else {
5698 FIXME("Unknown error setting the render target\n");
5700 This->sceneEnded = FALSE;
5701 return hr;
5704 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 HRESULT hr = WINED3D_OK;
5707 IWineD3DSurface *tmp;
5709 TRACE("(%p) Swapping z-buffer\n",This);
5711 if (pNewZStencil == This->stencilBufferTarget) {
5712 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5713 } else {
5714 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5715 * depending on the renter target implementation being used.
5716 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5717 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5718 * stencil buffer and incure an extra memory overhead
5719 ******************************************************/
5722 tmp = This->stencilBufferTarget;
5723 This->stencilBufferTarget = pNewZStencil;
5724 /* should we be calling the parent or the wined3d surface? */
5725 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5726 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5727 hr = WINED3D_OK;
5728 /** TODO: glEnable/glDisable on depth/stencil depending on
5729 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5730 **********************************************************/
5731 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5732 set_depth_stencil_fbo(iface, pNewZStencil);
5736 return hr;
5740 #ifdef GL_VERSION_1_3
5741 /* Internal functions not in DirectX */
5742 /** TODO: move this off to the opengl context manager
5743 *(the swapchain doesn't need to know anything about offscreen rendering!)
5744 ****************************************************/
5746 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5750 TRACE("(%p), %p\n", This, swapchain);
5752 if (swapchain->win != swapchain->drawable) {
5753 /* Set everything back the way it ws */
5754 swapchain->render_ctx = swapchain->glCtx;
5755 swapchain->drawable = swapchain->win;
5757 return WINED3D_OK;
5760 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5761 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5763 int i;
5764 unsigned int width;
5765 unsigned int height;
5766 WINED3DFORMAT format;
5767 WINED3DSURFACE_DESC surfaceDesc;
5768 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5769 surfaceDesc.Width = &width;
5770 surfaceDesc.Height = &height;
5771 surfaceDesc.Format = &format;
5772 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5773 *context = NULL;
5774 /* I need a get width/height function (and should do something with the format) */
5775 for (i = 0; i < CONTEXT_CACHE; ++i) {
5776 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5777 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5778 the pSurface can be set to 0 allowing it to be reused from cache **/
5779 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5780 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5781 *context = &This->contextCache[i];
5782 break;
5784 if (This->contextCache[i].Width == 0) {
5785 This->contextCache[i].pSurface = pSurface;
5786 This->contextCache[i].Width = width;
5787 This->contextCache[i].Height = height;
5788 *context = &This->contextCache[i];
5789 break;
5792 if (i == CONTEXT_CACHE) {
5793 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5794 glContext *dropContext = 0;
5795 for (i = 0; i < CONTEXT_CACHE; i++) {
5796 if (This->contextCache[i].usedcount < minUsage) {
5797 dropContext = &This->contextCache[i];
5798 minUsage = This->contextCache[i].usedcount;
5801 /* clean up the context (this doesn't work for ATI at the moment */
5802 #if 0
5803 glXDestroyContext(swapchain->display, dropContext->context);
5804 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5805 #endif
5806 FIXME("Leak\n");
5807 dropContext->Width = 0;
5808 dropContext->pSurface = pSurface;
5809 *context = dropContext;
5810 } else {
5811 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5812 for (i = 0; i < CONTEXT_CACHE; i++) {
5813 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
5817 if (*context != NULL)
5818 return WINED3D_OK;
5819 else
5820 return E_OUTOFMEMORY;
5822 #endif
5824 /* Reapply the device stateblock */
5825 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
5827 BOOL oldRecording;
5828 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5829 DWORD i;
5831 /* Disable recording */
5832 oldUpdateStateBlock = This->updateStateBlock;
5833 oldRecording= This->isRecordingState;
5834 This->isRecordingState = FALSE;
5835 This->updateStateBlock = This->stateBlock;
5837 /* Reapply the state block */
5838 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
5840 /* Temporaryily mark all render states dirty to force reapplication
5841 * until the context management for is integrated with the state management
5842 * The same for the pixel shader, sampler states and texture stage states are marked
5843 * dirty my StateBlock::Apply already
5845 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
5846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
5848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5850 /* Restore recording */
5851 This->isRecordingState = oldRecording;
5852 This->updateStateBlock = oldUpdateStateBlock;
5855 /* Set offscreen rendering. When rendering offscreen the surface will be
5856 * rendered upside down to compensate for the fact that D3D texture coordinates
5857 * are flipped compared to GL texture coordinates. The cullmode is affected by
5858 * this, so it must be updated. To update the cullmode stateblock recording has
5859 * to be temporarily disabled. The new state management code will hopefully
5860 * make this unnecessary */
5861 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
5863 BOOL oldRecording;
5864 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5866 /* Nothing to update, return. */
5867 if (This->render_offscreen == isTexture) return;
5869 /* Disable recording */
5870 oldUpdateStateBlock = This->updateStateBlock;
5871 oldRecording= This->isRecordingState;
5872 This->isRecordingState = FALSE;
5873 This->updateStateBlock = This->stateBlock;
5875 This->render_offscreen = isTexture;
5876 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
5877 This->depth_copy_state = WINED3D_DCS_COPY;
5879 This->last_was_rhw = FALSE;
5880 This->proj_valid = FALSE;
5881 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
5883 /* Restore recording */
5884 This->isRecordingState = oldRecording;
5885 This->updateStateBlock = oldUpdateStateBlock;
5888 /* Returns an array of compatible FBconfig(s).
5889 * The array must be freed with XFree. Requires ENTER_GL() */
5891 static GLXFBConfig* device_find_fbconfigs(
5892 IWineD3DDeviceImpl* This,
5893 IWineD3DSwapChainImpl* implicitSwapchainImpl,
5894 IWineD3DSurface* RenderSurface) {
5896 GLXFBConfig* cfgs = NULL;
5897 int nCfgs = 0;
5898 int attribs[256];
5899 int nAttribs = 0;
5901 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
5902 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
5903 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
5905 /**TODO:
5906 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5907 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5910 #define PUSH1(att) attribs[nAttribs++] = (att);
5911 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5913 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
5915 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
5916 PUSH2(GLX_X_RENDERABLE, TRUE);
5917 PUSH2(GLX_DOUBLEBUFFER, TRUE);
5918 TRACE("calling makeglcfg\n");
5919 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
5920 PUSH1(None);
5921 TRACE("calling chooseFGConfig\n");
5922 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5923 DefaultScreen(implicitSwapchainImpl->display),
5924 attribs, &nCfgs);
5925 if (cfgs == NULL) {
5926 /* OK we didn't find the exact config, so use any reasonable match */
5927 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
5928 why we failed. */
5929 static BOOL show_message = TRUE;
5930 if (show_message) {
5931 ERR("Failed to find exact match, finding alternative but you may "
5932 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
5933 show_message = FALSE;
5935 nAttribs = 0;
5936 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
5937 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
5938 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
5939 PUSH2(GLX_DOUBLEBUFFER, FALSE);
5940 TRACE("calling makeglcfg\n");
5941 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
5942 PUSH1(None);
5943 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5944 DefaultScreen(implicitSwapchainImpl->display),
5945 attribs, &nCfgs);
5948 if (cfgs == NULL) {
5949 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
5950 BackBufferFormat, debug_d3dformat(BackBufferFormat),
5951 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
5952 } else {
5953 #ifdef EXTRA_TRACES
5954 int i;
5955 for (i = 0; i < nCfgs; ++i) {
5956 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
5957 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
5958 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
5960 if (NULL != This->renderTarget) {
5961 glFlush();
5962 vcheckGLcall("glFlush");
5963 /** This is only useful if the old render target was a swapchain,
5964 * we need to supercede this with a function that displays
5965 * the current buffer on the screen. This is easy to do in glx1.3 but
5966 * we need to do copy-write pixels in glx 1.2.
5967 ************************************************/
5968 glXSwapBuffers(implicitSwapChainImpl->display,
5969 implicitSwapChainImpl->drawable);
5970 printf("Hit Enter to get next frame ...\n");
5971 getchar();
5973 #endif
5975 #undef PUSH1
5976 #undef PUSH2
5978 return cfgs;
5981 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
5982 * the functionality needs splitting up so that we don't do more than we should do.
5983 * this only seems to impact performance a little.
5984 ******************************/
5985 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5986 IWineD3DSurface *RenderSurface) {
5989 * Currently only active for GLX >= 1.3
5990 * for others versions we'll have to use GLXPixmaps
5992 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
5993 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
5994 * so only check OpenGL version
5995 * ..........................
5996 * I don't believe that it is a problem with NVidia headers,
5997 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
5998 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
5999 * ATI Note:
6000 * Your application will report GLX version 1.2 on glXQueryVersion.
6001 * However, it is safe to call the GLX 1.3 functions as described below.
6003 #if defined(GL_VERSION_1_3)
6005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6006 GLXFBConfig* cfgs = NULL;
6007 IWineD3DSwapChain *currentSwapchain;
6008 IWineD3DSwapChainImpl *currentSwapchainImpl;
6009 IWineD3DSwapChain *implicitSwapchain;
6010 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6011 IWineD3DSwapChain *renderSurfaceSwapchain;
6012 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6014 /* Obtain a reference to the device implicit swapchain,
6015 * the swapchain of the current render target,
6016 * and the swapchain of the new render target.
6017 * Fallback to device implicit swapchain if the current render target doesn't have one */
6018 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6019 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6020 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
6021 if (currentSwapchain == NULL)
6022 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6024 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6025 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6026 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6028 ENTER_GL();
6031 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6032 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6033 **********************************************************************/
6034 if (renderSurfaceSwapchain != NULL) {
6036 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6037 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6038 TRACE("making swapchain active\n");
6039 if (RenderSurface != This->render_targets[0]) {
6040 BOOL backbuf = FALSE;
6041 int i;
6043 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6044 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6045 backbuf = TRUE;
6046 break;
6050 if (backbuf) {
6051 } else {
6052 /* This could be flagged so that some operations work directly with the front buffer */
6053 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6055 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6056 renderSurfaceSwapchainImpl->win,
6057 renderSurfaceSwapchainImpl->glCtx) == False) {
6059 TRACE("Error in setting current context: context %p drawable %ld !\n",
6060 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6062 checkGLcall("glXMakeContextCurrent");
6064 /* Clean up the old context */
6065 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6067 /* Reapply the stateblock, and set the device not to render to texture */
6068 device_reapply_stateblock(This);
6069 device_render_to_texture(This, FALSE);
6072 /* Offscreen rendering: PBuffers (currently disabled).
6073 * Also note that this path is never reached if FBOs are supported */
6074 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6075 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6077 /** ********************************************************************
6078 * This is a quickly hacked out implementation of offscreen textures.
6079 * It will work in most cases but there may be problems if the client
6080 * modifies the texture directly, or expects the contents of the rendertarget
6081 * to be persistent.
6083 * There are some real speed vs compatibility issues here:
6084 * we should really use a new context for every texture, but that eats ram.
6085 * we should also be restoring the texture to the pbuffer but that eats CPU
6086 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6087 * but if this means reusing the display backbuffer then we need to make sure that
6088 * states are correctly preserved.
6089 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6090 * and gain a good performance increase at the cost of compatibility.
6091 * I would suggest that, when this is the case, a user configurable flag be made
6092 * available, allowing the user to choose the best emulated experience for them.
6093 *********************************************************************/
6095 XVisualInfo *visinfo;
6096 glContext *newContext;
6098 /* Here were using a shared context model */
6099 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6100 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6103 /* If the context doesn't exist then create a new one */
6104 /* TODO: This should really be part of findGlContext */
6105 if (NULL == newContext->context) {
6107 int attribs[256];
6108 int nAttribs = 0;
6110 TRACE("making new buffer\n");
6111 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6112 attribs[nAttribs++] = newContext->Width;
6113 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6114 attribs[nAttribs++] = newContext->Height;
6115 attribs[nAttribs++] = None;
6117 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6119 /** ****************************************
6120 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6121 *they note:
6122 * In future releases, we may provide the calls glXCreateNewContext,
6123 * glXQueryDrawable and glXMakeContextCurrent.
6124 * so until then we have to use glXGetVisualFromFBConfig &co..
6125 ********************************************/
6127 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6128 if (!visinfo) {
6129 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6130 } else {
6131 newContext->context = glXCreateContext(
6132 implicitSwapchainImpl->display, visinfo,
6133 implicitSwapchainImpl->glCtx, GL_TRUE);
6135 XFree(visinfo);
6138 if (NULL == newContext || NULL == newContext->context) {
6139 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6140 } else {
6141 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6142 if (glXMakeCurrent(implicitSwapchainImpl->display,
6143 newContext->drawable, newContext->context) == False) {
6145 TRACE("Error in setting current context: context %p drawable %ld\n",
6146 newContext->context, newContext->drawable);
6148 checkGLcall("glXMakeContextCurrent");
6150 /* Clean up the old context */
6151 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6153 /* Reapply stateblock, and set device to render to a texture */
6154 device_reapply_stateblock(This);
6155 device_render_to_texture(This, TRUE);
6157 /* Set the current context of the swapchain to the new context */
6158 implicitSwapchainImpl->drawable = newContext->drawable;
6159 implicitSwapchainImpl->render_ctx = newContext->context;
6161 } else {
6162 /* Same context, but update render_offscreen and cull mode */
6163 device_render_to_texture(This, TRUE);
6166 if (cfgs != NULL) XFree(cfgs);
6167 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6168 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6169 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6170 LEAVE_GL();
6171 #endif
6172 return WINED3D_OK;
6175 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6176 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6178 /* TODO: the use of Impl is deprecated. */
6179 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6181 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6183 /* some basic validation checks */
6184 if(This->cursorTexture) {
6185 ENTER_GL();
6186 glDeleteTextures(1, &This->cursorTexture);
6187 LEAVE_GL();
6188 This->cursorTexture = 0;
6191 if(pCursorBitmap) {
6192 /* MSDN: Cursor must be A8R8G8B8 */
6193 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6194 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6195 return WINED3DERR_INVALIDCALL;
6198 /* MSDN: Cursor must be smaller than the display mode */
6199 if(pSur->currentDesc.Width > This->ddraw_width ||
6200 pSur->currentDesc.Height > This->ddraw_height) {
6201 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);
6202 return WINED3DERR_INVALIDCALL;
6205 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6206 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6207 * Texture and Blitting code to draw the cursor
6209 pSur->Flags |= SFLAG_FORCELOAD;
6210 IWineD3DSurface_PreLoad(pCursorBitmap);
6211 pSur->Flags &= ~SFLAG_FORCELOAD;
6212 /* Do not store the surface's pointer because the application may release
6213 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6214 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6216 This->cursorTexture = pSur->glDescription.textureName;
6217 This->cursorWidth = pSur->currentDesc.Width;
6218 This->cursorHeight = pSur->currentDesc.Height;
6219 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6222 This->xHotSpot = XHotSpot;
6223 This->yHotSpot = YHotSpot;
6224 return WINED3D_OK;
6227 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6229 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6231 This->xScreenSpace = XScreenSpace;
6232 This->yScreenSpace = YScreenSpace;
6234 return;
6238 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6240 BOOL oldVisible = This->bCursorVisible;
6241 TRACE("(%p) : visible(%d)\n", This, bShow);
6243 if(This->cursorTexture)
6244 This->bCursorVisible = bShow;
6246 return oldVisible;
6249 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6251 TRACE("(%p) : state (%u)\n", This, This->state);
6252 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6253 switch (This->state) {
6254 case WINED3D_OK:
6255 return WINED3D_OK;
6256 case WINED3DERR_DEVICELOST:
6258 ResourceList *resourceList = This->resources;
6259 while (NULL != resourceList) {
6260 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6261 return WINED3DERR_DEVICENOTRESET;
6262 resourceList = resourceList->next;
6264 return WINED3DERR_DEVICELOST;
6266 case WINED3DERR_DRIVERINTERNALERROR:
6267 return WINED3DERR_DRIVERINTERNALERROR;
6270 /* Unknown state */
6271 return WINED3DERR_DRIVERINTERNALERROR;
6275 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6277 /** FIXME: Resource tracking needs to be done,
6278 * The closes we can do to this is set the priorities of all managed textures low
6279 * and then reset them.
6280 ***********************************************************/
6281 FIXME("(%p) : stub\n", This);
6282 return WINED3D_OK;
6285 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6286 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6287 if(surface->Flags & SFLAG_DIBSECTION) {
6288 /* Release the DC */
6289 SelectObject(surface->hDC, surface->dib.holdbitmap);
6290 DeleteDC(surface->hDC);
6291 /* Release the DIB section */
6292 DeleteObject(surface->dib.DIBsection);
6293 surface->dib.bitmap_data = NULL;
6294 surface->resource.allocatedMemory = NULL;
6295 surface->Flags &= ~SFLAG_DIBSECTION;
6297 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6298 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6299 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6300 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6301 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6302 } else {
6303 surface->pow2Width = surface->pow2Height = 1;
6304 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6305 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6307 if(surface->glDescription.textureName) {
6308 ENTER_GL();
6309 glDeleteTextures(1, &surface->glDescription.textureName);
6310 LEAVE_GL();
6311 surface->glDescription.textureName = 0;
6313 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6314 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6315 surface->Flags |= SFLAG_NONPOW2;
6316 } else {
6317 surface->Flags &= ~SFLAG_NONPOW2;
6319 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6320 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6323 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6325 IWineD3DSwapChainImpl *swapchain;
6326 HRESULT hr;
6327 BOOL DisplayModeChanged = FALSE;
6328 WINED3DDISPLAYMODE mode;
6329 TRACE("(%p)\n", This);
6331 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6332 if(FAILED(hr)) {
6333 ERR("Failed to get the first implicit swapchain\n");
6334 return hr;
6337 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6338 * on an existing gl context, so there's no real need for recreation.
6340 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6342 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6344 TRACE("New params:\n");
6345 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6346 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6347 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6348 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6349 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6350 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6351 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6352 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6353 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6354 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6355 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6356 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6357 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6359 /* No special treatment of these parameters. Just store them */
6360 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6361 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6362 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6363 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6365 /* What to do about these? */
6366 if(*pPresentationParameters->BackBufferCount != 0 &&
6367 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6368 ERR("Cannot change the back buffer count yet\n");
6370 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6371 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6372 ERR("Cannot change the back buffer format yet\n");
6374 if(*pPresentationParameters->hDeviceWindow != NULL &&
6375 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6376 ERR("Cannot change the device window yet\n");
6378 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6379 ERR("What do do about a changed auto depth stencil parameter?\n");
6382 if(*pPresentationParameters->Windowed) {
6383 mode.Width = swapchain->orig_width;
6384 mode.Height = swapchain->orig_height;
6385 mode.RefreshRate = 0;
6386 mode.Format = swapchain->presentParms.BackBufferFormat;
6387 } else {
6388 mode.Width = *pPresentationParameters->BackBufferWidth;
6389 mode.Height = *pPresentationParameters->BackBufferHeight;
6390 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6391 mode.Format = swapchain->presentParms.BackBufferFormat;
6394 /* Should Width == 800 && Height == 0 set 800x600? */
6395 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6396 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6397 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6399 WINED3DVIEWPORT vp;
6400 int i;
6402 vp.X = 0;
6403 vp.Y = 0;
6404 vp.Width = *pPresentationParameters->BackBufferWidth;
6405 vp.Height = *pPresentationParameters->BackBufferHeight;
6406 vp.MinZ = 0;
6407 vp.MaxZ = 1;
6409 if(!*pPresentationParameters->Windowed) {
6410 DisplayModeChanged = TRUE;
6412 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6413 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6415 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6416 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6417 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6420 /* Now set the new viewport */
6421 IWineD3DDevice_SetViewport(iface, &vp);
6424 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6425 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6426 DisplayModeChanged) {
6427 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6430 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6431 return WINED3D_OK;
6434 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6436 /** FIXME: always true at the moment **/
6437 if(!bEnableDialogs) {
6438 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6440 return WINED3D_OK;
6444 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6446 TRACE("(%p) : pParameters %p\n", This, pParameters);
6448 *pParameters = This->createParms;
6449 return WINED3D_OK;
6452 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6453 IWineD3DSwapChain *swapchain;
6454 HRESULT hrc = WINED3D_OK;
6456 TRACE("Relaying to swapchain\n");
6458 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6459 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6460 IWineD3DSwapChain_Release(swapchain);
6462 return;
6465 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6466 IWineD3DSwapChain *swapchain;
6467 HRESULT hrc = WINED3D_OK;
6469 TRACE("Relaying to swapchain\n");
6471 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6472 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6473 IWineD3DSwapChain_Release(swapchain);
6475 return;
6479 /** ********************************************************
6480 * Notification functions
6481 ** ********************************************************/
6482 /** This function must be called in the release of a resource when ref == 0,
6483 * the contents of resource must still be correct,
6484 * any handels to other resource held by the caller must be closed
6485 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6486 *****************************************************/
6487 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6489 ResourceList* resourceList;
6491 TRACE("(%p) : resource %p\n", This, resource);
6492 #if 0
6493 EnterCriticalSection(&resourceStoreCriticalSection);
6494 #endif
6495 /* add a new texture to the frot of the linked list */
6496 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6497 resourceList->resource = resource;
6499 /* Get the old head */
6500 resourceList->next = This->resources;
6502 This->resources = resourceList;
6503 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6505 #if 0
6506 LeaveCriticalSection(&resourceStoreCriticalSection);
6507 #endif
6508 return;
6511 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6513 ResourceList* resourceList = NULL;
6514 ResourceList* previousResourceList = NULL;
6516 TRACE("(%p) : resource %p\n", This, resource);
6518 #if 0
6519 EnterCriticalSection(&resourceStoreCriticalSection);
6520 #endif
6521 resourceList = This->resources;
6523 while (resourceList != NULL) {
6524 if(resourceList->resource == resource) break;
6525 previousResourceList = resourceList;
6526 resourceList = resourceList->next;
6529 if (resourceList == NULL) {
6530 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6531 #if 0
6532 LeaveCriticalSection(&resourceStoreCriticalSection);
6533 #endif
6534 return;
6535 } else {
6536 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6538 /* make sure we don't leave a hole in the list */
6539 if (previousResourceList != NULL) {
6540 previousResourceList->next = resourceList->next;
6541 } else {
6542 This->resources = resourceList->next;
6545 #if 0
6546 LeaveCriticalSection(&resourceStoreCriticalSection);
6547 #endif
6548 return;
6552 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6554 int counter;
6556 TRACE("(%p) : resource %p\n", This, resource);
6557 switch(IWineD3DResource_GetType(resource)){
6558 case WINED3DRTYPE_SURFACE:
6559 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6560 break;
6561 case WINED3DRTYPE_TEXTURE:
6562 case WINED3DRTYPE_CUBETEXTURE:
6563 case WINED3DRTYPE_VOLUMETEXTURE:
6564 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6565 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6566 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6567 This->stateBlock->textures[counter] = NULL;
6569 if (This->updateStateBlock != This->stateBlock ){
6570 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6571 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6572 This->updateStateBlock->textures[counter] = NULL;
6576 break;
6577 case WINED3DRTYPE_VOLUME:
6578 /* TODO: nothing really? */
6579 break;
6580 case WINED3DRTYPE_VERTEXBUFFER:
6581 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6583 int streamNumber;
6584 TRACE("Cleaning up stream pointers\n");
6586 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6587 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6588 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6590 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6591 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6592 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6593 This->updateStateBlock->streamSource[streamNumber] = 0;
6594 /* Set changed flag? */
6597 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) */
6598 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6599 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6600 This->stateBlock->streamSource[streamNumber] = 0;
6603 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6604 else { /* This shouldn't happen */
6605 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6607 #endif
6611 break;
6612 case WINED3DRTYPE_INDEXBUFFER:
6613 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6614 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6615 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6616 This->updateStateBlock->pIndexData = NULL;
6619 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6620 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6621 This->stateBlock->pIndexData = NULL;
6625 break;
6626 default:
6627 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6628 break;
6632 /* Remove the resoruce from the resourceStore */
6633 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6635 TRACE("Resource released\n");
6639 /**********************************************************
6640 * IWineD3DDevice VTbl follows
6641 **********************************************************/
6643 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6645 /*** IUnknown methods ***/
6646 IWineD3DDeviceImpl_QueryInterface,
6647 IWineD3DDeviceImpl_AddRef,
6648 IWineD3DDeviceImpl_Release,
6649 /*** IWineD3DDevice methods ***/
6650 IWineD3DDeviceImpl_GetParent,
6651 /*** Creation methods**/
6652 IWineD3DDeviceImpl_CreateVertexBuffer,
6653 IWineD3DDeviceImpl_CreateIndexBuffer,
6654 IWineD3DDeviceImpl_CreateStateBlock,
6655 IWineD3DDeviceImpl_CreateSurface,
6656 IWineD3DDeviceImpl_CreateTexture,
6657 IWineD3DDeviceImpl_CreateVolumeTexture,
6658 IWineD3DDeviceImpl_CreateVolume,
6659 IWineD3DDeviceImpl_CreateCubeTexture,
6660 IWineD3DDeviceImpl_CreateQuery,
6661 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6662 IWineD3DDeviceImpl_CreateVertexDeclaration,
6663 IWineD3DDeviceImpl_CreateVertexShader,
6664 IWineD3DDeviceImpl_CreatePixelShader,
6665 IWineD3DDeviceImpl_CreatePalette,
6666 /*** Odd functions **/
6667 IWineD3DDeviceImpl_Init3D,
6668 IWineD3DDeviceImpl_Uninit3D,
6669 IWineD3DDeviceImpl_SetFullscreen,
6670 IWineD3DDeviceImpl_EnumDisplayModes,
6671 IWineD3DDeviceImpl_EvictManagedResources,
6672 IWineD3DDeviceImpl_GetAvailableTextureMem,
6673 IWineD3DDeviceImpl_GetBackBuffer,
6674 IWineD3DDeviceImpl_GetCreationParameters,
6675 IWineD3DDeviceImpl_GetDeviceCaps,
6676 IWineD3DDeviceImpl_GetDirect3D,
6677 IWineD3DDeviceImpl_GetDisplayMode,
6678 IWineD3DDeviceImpl_SetDisplayMode,
6679 IWineD3DDeviceImpl_GetHWND,
6680 IWineD3DDeviceImpl_SetHWND,
6681 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6682 IWineD3DDeviceImpl_GetRasterStatus,
6683 IWineD3DDeviceImpl_GetSwapChain,
6684 IWineD3DDeviceImpl_Reset,
6685 IWineD3DDeviceImpl_SetDialogBoxMode,
6686 IWineD3DDeviceImpl_SetCursorProperties,
6687 IWineD3DDeviceImpl_SetCursorPosition,
6688 IWineD3DDeviceImpl_ShowCursor,
6689 IWineD3DDeviceImpl_TestCooperativeLevel,
6690 /*** Getters and setters **/
6691 IWineD3DDeviceImpl_SetClipPlane,
6692 IWineD3DDeviceImpl_GetClipPlane,
6693 IWineD3DDeviceImpl_SetClipStatus,
6694 IWineD3DDeviceImpl_GetClipStatus,
6695 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6696 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6697 IWineD3DDeviceImpl_SetDepthStencilSurface,
6698 IWineD3DDeviceImpl_GetDepthStencilSurface,
6699 IWineD3DDeviceImpl_SetFVF,
6700 IWineD3DDeviceImpl_GetFVF,
6701 IWineD3DDeviceImpl_SetGammaRamp,
6702 IWineD3DDeviceImpl_GetGammaRamp,
6703 IWineD3DDeviceImpl_SetIndices,
6704 IWineD3DDeviceImpl_GetIndices,
6705 IWineD3DDeviceImpl_SetBasevertexIndex,
6706 IWineD3DDeviceImpl_SetLight,
6707 IWineD3DDeviceImpl_GetLight,
6708 IWineD3DDeviceImpl_SetLightEnable,
6709 IWineD3DDeviceImpl_GetLightEnable,
6710 IWineD3DDeviceImpl_SetMaterial,
6711 IWineD3DDeviceImpl_GetMaterial,
6712 IWineD3DDeviceImpl_SetNPatchMode,
6713 IWineD3DDeviceImpl_GetNPatchMode,
6714 IWineD3DDeviceImpl_SetPaletteEntries,
6715 IWineD3DDeviceImpl_GetPaletteEntries,
6716 IWineD3DDeviceImpl_SetPixelShader,
6717 IWineD3DDeviceImpl_GetPixelShader,
6718 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6719 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6720 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6721 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6722 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6723 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6724 IWineD3DDeviceImpl_SetRenderState,
6725 IWineD3DDeviceImpl_GetRenderState,
6726 IWineD3DDeviceImpl_SetRenderTarget,
6727 IWineD3DDeviceImpl_GetRenderTarget,
6728 IWineD3DDeviceImpl_SetFrontBackBuffers,
6729 IWineD3DDeviceImpl_SetSamplerState,
6730 IWineD3DDeviceImpl_GetSamplerState,
6731 IWineD3DDeviceImpl_SetScissorRect,
6732 IWineD3DDeviceImpl_GetScissorRect,
6733 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6734 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6735 IWineD3DDeviceImpl_SetStreamSource,
6736 IWineD3DDeviceImpl_GetStreamSource,
6737 IWineD3DDeviceImpl_SetStreamSourceFreq,
6738 IWineD3DDeviceImpl_GetStreamSourceFreq,
6739 IWineD3DDeviceImpl_SetTexture,
6740 IWineD3DDeviceImpl_GetTexture,
6741 IWineD3DDeviceImpl_SetTextureStageState,
6742 IWineD3DDeviceImpl_GetTextureStageState,
6743 IWineD3DDeviceImpl_SetTransform,
6744 IWineD3DDeviceImpl_GetTransform,
6745 IWineD3DDeviceImpl_SetVertexDeclaration,
6746 IWineD3DDeviceImpl_GetVertexDeclaration,
6747 IWineD3DDeviceImpl_SetVertexShader,
6748 IWineD3DDeviceImpl_GetVertexShader,
6749 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6750 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6751 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6752 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6753 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6754 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6755 IWineD3DDeviceImpl_SetViewport,
6756 IWineD3DDeviceImpl_GetViewport,
6757 IWineD3DDeviceImpl_MultiplyTransform,
6758 IWineD3DDeviceImpl_ValidateDevice,
6759 IWineD3DDeviceImpl_ProcessVertices,
6760 /*** State block ***/
6761 IWineD3DDeviceImpl_BeginStateBlock,
6762 IWineD3DDeviceImpl_EndStateBlock,
6763 /*** Scene management ***/
6764 IWineD3DDeviceImpl_BeginScene,
6765 IWineD3DDeviceImpl_EndScene,
6766 IWineD3DDeviceImpl_Present,
6767 IWineD3DDeviceImpl_Clear,
6768 /*** Drawing ***/
6769 IWineD3DDeviceImpl_DrawPrimitive,
6770 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6771 IWineD3DDeviceImpl_DrawPrimitiveUP,
6772 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6773 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6774 IWineD3DDeviceImpl_DrawRectPatch,
6775 IWineD3DDeviceImpl_DrawTriPatch,
6776 IWineD3DDeviceImpl_DeletePatch,
6777 IWineD3DDeviceImpl_ColorFill,
6778 IWineD3DDeviceImpl_UpdateTexture,
6779 IWineD3DDeviceImpl_UpdateSurface,
6780 IWineD3DDeviceImpl_StretchRect,
6781 IWineD3DDeviceImpl_GetRenderTargetData,
6782 IWineD3DDeviceImpl_GetFrontBufferData,
6783 /*** object tracking ***/
6784 IWineD3DDeviceImpl_ResourceReleased
6788 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6789 WINED3DRS_ALPHABLENDENABLE ,
6790 WINED3DRS_ALPHAFUNC ,
6791 WINED3DRS_ALPHAREF ,
6792 WINED3DRS_ALPHATESTENABLE ,
6793 WINED3DRS_BLENDOP ,
6794 WINED3DRS_COLORWRITEENABLE ,
6795 WINED3DRS_DESTBLEND ,
6796 WINED3DRS_DITHERENABLE ,
6797 WINED3DRS_FILLMODE ,
6798 WINED3DRS_FOGDENSITY ,
6799 WINED3DRS_FOGEND ,
6800 WINED3DRS_FOGSTART ,
6801 WINED3DRS_LASTPIXEL ,
6802 WINED3DRS_SHADEMODE ,
6803 WINED3DRS_SRCBLEND ,
6804 WINED3DRS_STENCILENABLE ,
6805 WINED3DRS_STENCILFAIL ,
6806 WINED3DRS_STENCILFUNC ,
6807 WINED3DRS_STENCILMASK ,
6808 WINED3DRS_STENCILPASS ,
6809 WINED3DRS_STENCILREF ,
6810 WINED3DRS_STENCILWRITEMASK ,
6811 WINED3DRS_STENCILZFAIL ,
6812 WINED3DRS_TEXTUREFACTOR ,
6813 WINED3DRS_WRAP0 ,
6814 WINED3DRS_WRAP1 ,
6815 WINED3DRS_WRAP2 ,
6816 WINED3DRS_WRAP3 ,
6817 WINED3DRS_WRAP4 ,
6818 WINED3DRS_WRAP5 ,
6819 WINED3DRS_WRAP6 ,
6820 WINED3DRS_WRAP7 ,
6821 WINED3DRS_ZENABLE ,
6822 WINED3DRS_ZFUNC ,
6823 WINED3DRS_ZWRITEENABLE
6826 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6827 WINED3DTSS_ADDRESSW ,
6828 WINED3DTSS_ALPHAARG0 ,
6829 WINED3DTSS_ALPHAARG1 ,
6830 WINED3DTSS_ALPHAARG2 ,
6831 WINED3DTSS_ALPHAOP ,
6832 WINED3DTSS_BUMPENVLOFFSET ,
6833 WINED3DTSS_BUMPENVLSCALE ,
6834 WINED3DTSS_BUMPENVMAT00 ,
6835 WINED3DTSS_BUMPENVMAT01 ,
6836 WINED3DTSS_BUMPENVMAT10 ,
6837 WINED3DTSS_BUMPENVMAT11 ,
6838 WINED3DTSS_COLORARG0 ,
6839 WINED3DTSS_COLORARG1 ,
6840 WINED3DTSS_COLORARG2 ,
6841 WINED3DTSS_COLOROP ,
6842 WINED3DTSS_RESULTARG ,
6843 WINED3DTSS_TEXCOORDINDEX ,
6844 WINED3DTSS_TEXTURETRANSFORMFLAGS
6847 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6848 WINED3DSAMP_ADDRESSU ,
6849 WINED3DSAMP_ADDRESSV ,
6850 WINED3DSAMP_ADDRESSW ,
6851 WINED3DSAMP_BORDERCOLOR ,
6852 WINED3DSAMP_MAGFILTER ,
6853 WINED3DSAMP_MINFILTER ,
6854 WINED3DSAMP_MIPFILTER ,
6855 WINED3DSAMP_MIPMAPLODBIAS ,
6856 WINED3DSAMP_MAXMIPLEVEL ,
6857 WINED3DSAMP_MAXANISOTROPY ,
6858 WINED3DSAMP_SRGBTEXTURE ,
6859 WINED3DSAMP_ELEMENTINDEX
6862 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6863 WINED3DRS_AMBIENT ,
6864 WINED3DRS_AMBIENTMATERIALSOURCE ,
6865 WINED3DRS_CLIPPING ,
6866 WINED3DRS_CLIPPLANEENABLE ,
6867 WINED3DRS_COLORVERTEX ,
6868 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6869 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6870 WINED3DRS_FOGDENSITY ,
6871 WINED3DRS_FOGEND ,
6872 WINED3DRS_FOGSTART ,
6873 WINED3DRS_FOGTABLEMODE ,
6874 WINED3DRS_FOGVERTEXMODE ,
6875 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6876 WINED3DRS_LIGHTING ,
6877 WINED3DRS_LOCALVIEWER ,
6878 WINED3DRS_MULTISAMPLEANTIALIAS ,
6879 WINED3DRS_MULTISAMPLEMASK ,
6880 WINED3DRS_NORMALIZENORMALS ,
6881 WINED3DRS_PATCHEDGESTYLE ,
6882 WINED3DRS_POINTSCALE_A ,
6883 WINED3DRS_POINTSCALE_B ,
6884 WINED3DRS_POINTSCALE_C ,
6885 WINED3DRS_POINTSCALEENABLE ,
6886 WINED3DRS_POINTSIZE ,
6887 WINED3DRS_POINTSIZE_MAX ,
6888 WINED3DRS_POINTSIZE_MIN ,
6889 WINED3DRS_POINTSPRITEENABLE ,
6890 WINED3DRS_RANGEFOGENABLE ,
6891 WINED3DRS_SPECULARMATERIALSOURCE ,
6892 WINED3DRS_TWEENFACTOR ,
6893 WINED3DRS_VERTEXBLEND
6896 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6897 WINED3DTSS_TEXCOORDINDEX ,
6898 WINED3DTSS_TEXTURETRANSFORMFLAGS
6901 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6902 WINED3DSAMP_DMAPOFFSET
6905 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6906 DWORD rep = StateTable[state].representative;
6907 DWORD idx;
6908 BYTE shift;
6910 if(!rep || isStateDirty(This, rep)) return;
6912 This->dirtyArray[This->numDirtyEntries++] = rep;
6913 idx = rep >> 5;
6914 shift = rep & 0x1f;
6915 This->isStateDirty[idx] |= (1 << shift);