2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * Utility functions follow
153 **********************************************************/
154 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
155 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
158 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
162 glMatrixMode(GL_MODELVIEW);
164 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
167 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
168 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
169 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
170 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
171 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
172 checkGLcall("glLightfv");
175 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
176 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
177 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
178 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
179 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
180 checkGLcall("glLightfv");
183 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
184 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
185 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
186 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
187 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
188 checkGLcall("glLightfv");
190 /* Attenuation - Are these right? guessing... */
191 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
192 checkGLcall("glLightf");
193 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
194 checkGLcall("glLightf");
196 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
197 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
199 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
202 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
203 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
204 checkGLcall("glLightf");
206 switch (lightInfo->OriginalParms.Type) {
207 case WINED3DLIGHT_POINT:
209 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
210 checkGLcall("glLightfv");
211 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
212 checkGLcall("glLightf");
216 case WINED3DLIGHT_SPOT:
218 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
219 checkGLcall("glLightfv");
221 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
222 checkGLcall("glLightfv");
223 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
224 checkGLcall("glLightf");
225 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
226 checkGLcall("glLightf");
230 case WINED3DLIGHT_DIRECTIONAL:
232 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
233 checkGLcall("glLightfv");
234 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
235 checkGLcall("glLightf");
236 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
237 checkGLcall("glLightf");
241 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
244 /* Restore the modelview matrix */
248 /**********************************************************
249 * GLSL helper functions follow
250 **********************************************************/
252 /** Detach the GLSL pixel or vertex shader object from the shader program */
253 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
257 if (shaderObj != 0 && programId != 0) {
258 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
259 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
260 checkGLcall("glDetachObjectARB");
264 /** Delete a GLSL shader program */
265 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
270 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
271 GL_EXTCALL(glDeleteObjectARB(obj));
272 checkGLcall("glDeleteObjectARB");
276 /** Delete the list of linked programs this shader is associated with.
277 * Also at this point, check to see if there are any objects left attached
278 * to each GLSL program. If not, delete the GLSL program object.
279 * This will be run when a device is released. */
280 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
282 struct list *ptr = NULL;
283 struct glsl_shader_prog_link *curLink = NULL;
284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
288 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
289 (one pixel shader and one vertex shader at most) */
291 ptr = list_head( &This->glsl_shader_progs );
293 /* First, get the current item,
294 * save the link to the next pointer,
295 * detach and delete shader objects,
296 * then de-allocate the list item's memory */
297 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
298 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* See if this object is still attached to the program - it may have been detached already */
301 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
302 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
303 for (i = 0; i < numAttached; i++) {
304 detach_glsl_shader(iface, objList[i], curLink->programId);
307 delete_glsl_shader_program(iface, curLink->programId);
309 /* Free the uniform locations */
310 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
311 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
313 /* Free the memory for this list item */
314 HeapFree(GetProcessHeap(), 0, curLink);
318 /**********************************************************
319 * IUnknown parts follows
320 **********************************************************/
322 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
326 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
327 if (IsEqualGUID(riid, &IID_IUnknown)
328 || IsEqualGUID(riid, &IID_IWineD3DBase)
329 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
330 IUnknown_AddRef(iface);
335 return E_NOINTERFACE;
338 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
340 ULONG refCount = InterlockedIncrement(&This->ref);
342 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
346 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
348 ULONG refCount = InterlockedDecrement(&This->ref);
350 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
354 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
357 HeapFree(GetProcessHeap(), 0, This->render_targets);
359 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
361 /* TODO: Clean up all the surfaces and textures! */
362 /* NOTE: You must release the parent if the object was created via a callback
363 ** ***************************/
365 /* Delete any GLSL shader programs that may exist */
366 if (This->vs_selected_mode == SHADER_GLSL ||
367 This->ps_selected_mode == SHADER_GLSL)
368 delete_glsl_shader_list(iface);
370 /* Release the update stateblock */
371 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
372 if(This->updateStateBlock != This->stateBlock)
373 FIXME("(%p) Something's still holding the Update stateblock\n",This);
375 This->updateStateBlock = NULL;
376 { /* because were not doing proper internal refcounts releasing the primary state block
377 causes recursion with the extra checks in ResourceReleased, to avoid this we have
378 to set this->stateBlock = NULL; first */
379 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
380 This->stateBlock = NULL;
382 /* Release the stateblock */
383 if(IWineD3DStateBlock_Release(stateBlock) > 0){
384 FIXME("(%p) Something's still holding the Update stateblock\n",This);
388 if (This->resources != NULL ) {
389 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
390 dumpResources(This->resources);
394 IWineD3D_Release(This->wineD3D);
395 This->wineD3D = NULL;
396 HeapFree(GetProcessHeap(), 0, This);
397 TRACE("Freed device %p\n", This);
403 /**********************************************************
404 * IWineD3DDevice implementation follows
405 **********************************************************/
406 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
408 *pParent = This->parent;
409 IUnknown_AddRef(This->parent);
413 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
414 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
415 GLenum error, glUsage;
416 DWORD vboUsage = object->resource.usage;
417 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
418 WARN("Creating a vbo failed once, not trying again\n");
422 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
425 /* Make sure that the gl error is cleared. Do not use checkGLcall
426 * here because checkGLcall just prints a fixme and continues. However,
427 * if an error during VBO creation occurs we can fall back to non-vbo operation
428 * with full functionality(but performance loss)
430 while(glGetError() != GL_NO_ERROR);
432 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
433 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
434 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
435 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
436 * to check if the rhw and color values are in the correct format.
439 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
440 error = glGetError();
441 if(object->vbo == 0 || error != GL_NO_ERROR) {
442 WARN("Failed to create a VBO with error %d\n", error);
446 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
447 error = glGetError();
448 if(error != GL_NO_ERROR) {
449 WARN("Failed to bind the VBO, error %d\n", error);
453 /* Don't use static, because dx apps tend to update the buffer
454 * quite often even if they specify 0 usage
456 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
457 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
458 TRACE("Gl usage = GL_STREAM_DRAW\n");
459 glUsage = GL_STREAM_DRAW_ARB;
461 case D3DUSAGE_WRITEONLY:
462 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
463 glUsage = GL_DYNAMIC_DRAW_ARB;
465 case D3DUSAGE_DYNAMIC:
466 TRACE("Gl usage = GL_STREAM_COPY\n");
467 glUsage = GL_STREAM_COPY_ARB;
470 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
471 glUsage = GL_DYNAMIC_COPY_ARB;
475 /* Reserve memory for the buffer. The amount of data won't change
476 * so we are safe with calling glBufferData once with a NULL ptr and
477 * calling glBufferSubData on updates
479 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
480 error = glGetError();
481 if(error != GL_NO_ERROR) {
482 WARN("glBufferDataARB failed with error %d\n", error);
490 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
491 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
492 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
494 object->Flags |= VBFLAG_VBOCREATEFAIL;
499 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
500 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
503 IWineD3DVertexBufferImpl *object;
504 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
505 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
507 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
509 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
510 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
512 if(Size == 0) return WINED3DERR_INVALIDCALL;
514 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
515 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
519 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
520 * drawStridedFast (half-life 2).
522 * Basically converting the vertices in the buffer is quite expensive, and observations
523 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
524 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
526 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
527 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
528 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
529 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
531 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
532 * more. In this call we can convert dx7 buffers too.
534 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
535 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
536 (dxVersion > 7 || !conv) ) {
539 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
540 if(dxVersion == 7 && object->vbo) {
541 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
542 object->resource.allocatedMemory = NULL;
549 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
550 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
551 HANDLE *sharedHandle, IUnknown *parent) {
552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
553 IWineD3DIndexBufferImpl *object;
554 TRACE("(%p) Creating index buffer\n", This);
556 /* Allocate the storage for the device */
557 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
560 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
561 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
564 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
565 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
566 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
571 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
574 IWineD3DStateBlockImpl *object;
578 D3DCREATEOBJECTINSTANCE(object, StateBlock)
579 object->blockType = Type;
581 /* Special case - Used during initialization to produce a placeholder stateblock
582 so other functions called can update a state block */
583 if (Type == WINED3DSBT_INIT) {
584 /* Don't bother increasing the reference count otherwise a device will never
585 be freed due to circular dependencies */
589 temp_result = allocate_shader_constants(object);
590 if (WINED3D_OK != temp_result)
593 /* Otherwise, might as well set the whole state block to the appropriate values */
594 if (This->stateBlock != NULL)
595 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
597 memset(object->streamFreq, 1, sizeof(object->streamFreq));
599 /* Reset the ref and type after kludging it */
600 object->wineD3DDevice = This;
602 object->blockType = Type;
604 TRACE("Updating changed flags appropriate for type %d\n", Type);
606 if (Type == WINED3DSBT_ALL) {
608 TRACE("ALL => Pretend everything has changed\n");
609 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
611 } else if (Type == WINED3DSBT_PIXELSTATE) {
613 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
614 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
616 object->changed.pixelShader = TRUE;
618 /* Pixel Shader Constants */
619 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
620 object->changed.pixelShaderConstantsF[i] = TRUE;
621 for (i = 0; i < MAX_CONST_B; ++i)
622 object->changed.pixelShaderConstantsB[i] = TRUE;
623 for (i = 0; i < MAX_CONST_I; ++i)
624 object->changed.pixelShaderConstantsI[i] = TRUE;
626 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
627 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
629 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
630 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
631 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
634 for (j = 0 ; j < 16; j++) {
635 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
637 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
641 } else if (Type == WINED3DSBT_VERTEXSTATE) {
643 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
644 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
646 object->changed.vertexShader = TRUE;
648 /* Vertex Shader Constants */
649 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
650 object->changed.vertexShaderConstantsF[i] = TRUE;
651 for (i = 0; i < MAX_CONST_B; ++i)
652 object->changed.vertexShaderConstantsB[i] = TRUE;
653 for (i = 0; i < MAX_CONST_I; ++i)
654 object->changed.vertexShaderConstantsI[i] = TRUE;
656 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
657 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
659 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
660 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
661 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
664 for (j = 0 ; j < 16; j++){
665 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
666 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
670 /* Duplicate light chain */
672 PLIGHTINFOEL *src = NULL;
673 PLIGHTINFOEL *dst = NULL;
674 PLIGHTINFOEL *newEl = NULL;
675 src = This->stateBlock->lights;
676 object->lights = NULL;
680 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
681 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
682 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
684 newEl->changed = TRUE;
685 newEl->enabledChanged = TRUE;
687 object->lights = newEl;
698 FIXME("Unrecognized state block type %d\n", Type);
701 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
706 /* ************************************
708 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
711 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
713 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
715 ******************************** */
717 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
719 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
720 unsigned int pow2Width, pow2Height;
721 unsigned int Size = 1;
722 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
723 TRACE("(%p) Create surface\n",This);
725 /** FIXME: Check ranges on the inputs are valid
728 * [in] Quality level. The valid range is between zero and one less than the level
729 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
730 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
731 * values of paired render targets, depth stencil surfaces, and the MultiSample type
733 *******************************/
738 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
740 * If this flag is set, the contents of the depth stencil buffer will be
741 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
742 * with a different depth surface.
744 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
745 ***************************/
747 if(MultisampleQuality < 0) {
748 FIXME("Invalid multisample level %d\n", MultisampleQuality);
749 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
752 if(MultisampleQuality > 0) {
753 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
754 MultisampleQuality=0;
757 /** FIXME: Check that the format is supported
759 *******************************/
761 /* Non-power2 support */
762 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
766 /* Find the nearest pow2 match */
767 pow2Width = pow2Height = 1;
768 while (pow2Width < Width) pow2Width <<= 1;
769 while (pow2Height < Height) pow2Height <<= 1;
772 if (pow2Width > Width || pow2Height > Height) {
773 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
774 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
775 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
776 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
777 This, Width, Height);
778 return WINED3DERR_NOTAVAILABLE;
782 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
783 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
785 *********************************/
786 if (WINED3DFMT_UNKNOWN == Format) {
788 } else if (Format == WINED3DFMT_DXT1) {
789 /* DXT1 is half byte per pixel */
790 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
792 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
793 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
794 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
796 /* The pitch is a multiple of 4 bytes */
797 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
801 /** Create and initialise the surface resource **/
802 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
803 /* "Standalone" surface */
804 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
806 object->currentDesc.Width = Width;
807 object->currentDesc.Height = Height;
808 object->currentDesc.MultiSampleType = MultiSample;
809 object->currentDesc.MultiSampleQuality = MultisampleQuality;
811 /* Setup some glformat defaults */
812 object->glDescription.glFormat = tableEntry->glFormat;
813 object->glDescription.glFormatInternal = tableEntry->glInternal;
814 object->glDescription.glType = tableEntry->glType;
816 object->glDescription.textureName = 0;
817 object->glDescription.level = Level;
818 object->glDescription.target = GL_TEXTURE_2D;
821 object->pow2Width = pow2Width;
822 object->pow2Height = pow2Height;
825 object->Flags = 0; /* We start without flags set */
826 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
827 object->Flags |= Discard ? SFLAG_DISCARD : 0;
828 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
829 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
832 if (WINED3DFMT_UNKNOWN != Format) {
833 object->bytesPerPixel = tableEntry->bpp;
834 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
835 object->pow2Size *= pow2Height;
837 object->bytesPerPixel = 0;
838 object->pow2Size = 0;
841 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
843 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
845 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
846 * this function is too deep to need to care about things like this.
847 * Levels need to be checked too, and possibly Type since they all affect what can be done.
848 * ****************************************/
850 case WINED3DPOOL_SCRATCH:
852 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
853 "which are mutually exclusive, setting lockable to TRUE\n");
856 case WINED3DPOOL_SYSTEMMEM:
857 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
858 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
859 case WINED3DPOOL_MANAGED:
860 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
861 "Usage of DYNAMIC which are mutually exclusive, not doing "
862 "anything just telling you.\n");
864 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
865 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
866 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
867 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
870 FIXME("(%p) Unknown pool %d\n", This, Pool);
874 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
875 FIXME("Trying to create a render target that isn't in the default pool\n");
878 /* mark the texture as dirty so that it gets loaded first time around*/
879 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
880 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
881 This, Width, Height, Format, debug_d3dformat(Format),
882 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
884 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
885 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
886 This->ddraw_primary = (IWineD3DSurface *) object;
888 /* Look at the implementation and set the correct Vtable */
891 /* Nothing to do, it's set already */
895 object->lpVtbl = &IWineGDISurface_Vtbl;
899 /* To be sure to catch this */
900 ERR("Unknown requested surface implementation %d!\n", Impl);
901 IWineD3DSurface_Release((IWineD3DSurface *) object);
902 return WINED3DERR_INVALIDCALL;
905 /* Call the private setup routine */
906 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
910 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
911 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
912 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
913 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
916 IWineD3DTextureImpl *object;
921 unsigned int pow2Width;
922 unsigned int pow2Height;
925 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
926 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
927 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
929 /* TODO: It should only be possible to create textures for formats
930 that are reported as supported */
931 if (WINED3DFMT_UNKNOWN >= Format) {
932 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
933 return WINED3DERR_INVALIDCALL;
936 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
937 D3DINITIALIZEBASETEXTURE(object->baseTexture);
938 object->width = Width;
939 object->height = Height;
941 /** Non-power2 support **/
942 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
946 /* Find the nearest pow2 match */
947 pow2Width = pow2Height = 1;
948 while (pow2Width < Width) pow2Width <<= 1;
949 while (pow2Height < Height) pow2Height <<= 1;
952 /** FIXME: add support for real non-power-two if it's provided by the video card **/
953 /* Precalculated scaling for 'faked' non power of two texture coords */
954 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
955 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
956 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
958 /* Calculate levels for mip mapping */
960 TRACE("calculating levels %d\n", object->baseTexture.levels);
961 object->baseTexture.levels++;
964 while (tmpW > 1 || tmpH > 1) {
965 tmpW = max(1, tmpW >> 1);
966 tmpH = max(1, tmpH >> 1);
967 object->baseTexture.levels++;
969 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
972 /* Generate all the surfaces */
975 for (i = 0; i < object->baseTexture.levels; i++)
977 /* use the callback to create the texture surface */
978 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
979 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
980 FIXME("Failed to create surface %p\n", object);
982 object->surfaces[i] = NULL;
983 IWineD3DTexture_Release((IWineD3DTexture *)object);
989 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
990 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
991 /* calculate the next mipmap level */
992 tmpW = max(1, tmpW >> 1);
993 tmpH = max(1, tmpH >> 1);
996 TRACE("(%p) : Created texture %p\n", This, object);
1000 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1001 UINT Width, UINT Height, UINT Depth,
1002 UINT Levels, DWORD Usage,
1003 WINED3DFORMAT Format, WINED3DPOOL Pool,
1004 IWineD3DVolumeTexture **ppVolumeTexture,
1005 HANDLE *pSharedHandle, IUnknown *parent,
1006 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DVolumeTextureImpl *object;
1015 /* TODO: It should only be possible to create textures for formats
1016 that are reported as supported */
1017 if (WINED3DFMT_UNKNOWN >= Format) {
1018 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1019 return WINED3DERR_INVALIDCALL;
1022 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1023 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1025 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1026 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1028 object->width = Width;
1029 object->height = Height;
1030 object->depth = Depth;
1032 /* Calculate levels for mip mapping */
1034 object->baseTexture.levels++;
1038 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1039 tmpW = max(1, tmpW >> 1);
1040 tmpH = max(1, tmpH >> 1);
1041 tmpD = max(1, tmpD >> 1);
1042 object->baseTexture.levels++;
1044 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1047 /* Generate all the surfaces */
1052 for (i = 0; i < object->baseTexture.levels; i++)
1054 /* Create the volume */
1055 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1056 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1058 /* Set its container to this object */
1059 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1061 /* calcualte the next mipmap level */
1062 tmpW = max(1, tmpW >> 1);
1063 tmpH = max(1, tmpH >> 1);
1064 tmpD = max(1, tmpD >> 1);
1067 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1068 TRACE("(%p) : Created volume texture %p\n", This, object);
1072 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1073 UINT Width, UINT Height, UINT Depth,
1075 WINED3DFORMAT Format, WINED3DPOOL Pool,
1076 IWineD3DVolume** ppVolume,
1077 HANDLE* pSharedHandle, IUnknown *parent) {
1079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1080 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1081 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1083 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1085 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1086 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1088 object->currentDesc.Width = Width;
1089 object->currentDesc.Height = Height;
1090 object->currentDesc.Depth = Depth;
1091 object->bytesPerPixel = formatDesc->bpp;
1093 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1094 object->lockable = TRUE;
1095 object->locked = FALSE;
1096 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1097 object->dirty = TRUE;
1099 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1103 UINT Levels, DWORD Usage,
1104 WINED3DFORMAT Format, WINED3DPOOL Pool,
1105 IWineD3DCubeTexture **ppCubeTexture,
1106 HANDLE *pSharedHandle, IUnknown *parent,
1107 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1110 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1114 unsigned int pow2EdgeLength = EdgeLength;
1116 /* TODO: It should only be possible to create textures for formats
1117 that are reported as supported */
1118 if (WINED3DFMT_UNKNOWN >= Format) {
1119 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1120 return WINED3DERR_INVALIDCALL;
1123 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1124 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1126 TRACE("(%p) Create Cube Texture\n", This);
1128 /** Non-power2 support **/
1130 /* Find the nearest pow2 match */
1132 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1134 object->edgeLength = EdgeLength;
1135 /* TODO: support for native non-power 2 */
1136 /* Precalculated scaling for 'faked' non power of two texture coords */
1137 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1139 /* Calculate levels for mip mapping */
1141 object->baseTexture.levels++;
1144 tmpW = max(1, tmpW >> 1);
1145 object->baseTexture.levels++;
1147 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1150 /* Generate all the surfaces */
1152 for (i = 0; i < object->baseTexture.levels; i++) {
1154 /* Create the 6 faces */
1155 for (j = 0; j < 6; j++) {
1157 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1158 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1160 if(hr!= WINED3D_OK) {
1164 for (l = 0; l < j; l++) {
1165 IWineD3DSurface_Release(object->surfaces[j][i]);
1167 for (k = 0; k < i; k++) {
1168 for (l = 0; l < 6; l++) {
1169 IWineD3DSurface_Release(object->surfaces[l][j]);
1173 FIXME("(%p) Failed to create surface\n",object);
1174 HeapFree(GetProcessHeap(),0,object);
1175 *ppCubeTexture = NULL;
1178 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1179 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1181 tmpW = max(1, tmpW >> 1);
1184 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1185 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1189 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1191 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1193 if (NULL == ppQuery) {
1194 /* Just a check to see if we support this type of query */
1195 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1197 case WINED3DQUERYTYPE_OCCLUSION:
1198 TRACE("(%p) occlusion query\n", This);
1199 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1202 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_EVENT:
1208 case WINED3DQUERYTYPE_TIMESTAMP:
1209 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1210 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1211 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1212 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1213 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1214 case WINED3DQUERYTYPE_PIXELTIMINGS:
1215 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1216 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1218 FIXME("(%p) Unhandled query type %d\n", This, Type);
1223 D3DCREATEOBJECTINSTANCE(object, Query)
1224 object->type = Type;
1225 /* allocated the 'extended' data based on the type of query requested */
1227 case WINED3DQUERYTYPE_OCCLUSION:
1228 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1229 TRACE("(%p) Allocating data for an occlusion query\n", This);
1230 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1231 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1234 case WINED3DQUERYTYPE_VCACHE:
1235 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1236 case WINED3DQUERYTYPE_VERTEXSTATS:
1237 case WINED3DQUERYTYPE_EVENT:
1238 case WINED3DQUERYTYPE_TIMESTAMP:
1239 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1240 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1241 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1242 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1243 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1244 case WINED3DQUERYTYPE_PIXELTIMINGS:
1245 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1246 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1248 object->extendedData = 0;
1249 FIXME("(%p) Unhandled query type %d\n",This , Type);
1251 TRACE("(%p) : Created Query %p\n", This, object);
1255 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1256 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1258 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1259 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1263 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1265 XVisualInfo template;
1266 GLXContext oldContext;
1267 Drawable oldDrawable;
1268 HRESULT hr = WINED3D_OK;
1270 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1272 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1273 * does a device hold a reference to a swap chain giving them a lifetime of the device
1274 * or does the swap chain notify the device of its destruction.
1275 *******************************/
1277 /* Check the params */
1278 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1279 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1280 return WINED3DERR_INVALIDCALL;
1281 } else if (*pPresentationParameters->BackBufferCount > 1) {
1282 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");
1285 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1287 /*********************
1288 * Lookup the window Handle and the relating X window handle
1289 ********************/
1291 /* Setup hwnd we are using, plus which display this equates to */
1292 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1293 if (!object->win_handle) {
1294 object->win_handle = This->createParms.hFocusWindow;
1297 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1298 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1299 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1300 return WINED3DERR_NOTAVAILABLE;
1302 hDc = GetDC(object->win_handle);
1303 object->display = get_display(hDc);
1304 ReleaseDC(object->win_handle, hDc);
1305 TRACE("Using a display of %p %p\n", object->display, hDc);
1307 if (NULL == object->display || NULL == hDc) {
1308 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1309 return WINED3DERR_NOTAVAILABLE;
1312 if (object->win == 0) {
1313 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1314 return WINED3DERR_NOTAVAILABLE;
1317 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1318 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1321 * Create an opengl context for the display visual
1322 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1323 * use different properties after that point in time. FIXME: How to handle when requested format
1324 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1325 * it chooses is identical to the one already being used!
1326 **********************************/
1328 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1331 /* Create a new context for this swapchain */
1332 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1333 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1334 (or the best possible if none is requested) */
1335 TRACE("Found x visual ID : %ld\n", template.visualid);
1337 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1338 if (NULL == object->visInfo) {
1339 ERR("cannot really get XVisual\n");
1341 return WINED3DERR_NOTAVAILABLE;
1344 /* Write out some debug info about the visual/s */
1345 TRACE("Using x visual ID : %ld\n", template.visualid);
1346 TRACE(" visual info: %p\n", object->visInfo);
1347 TRACE(" num items : %d\n", num);
1348 for (n = 0;n < num; n++) {
1349 TRACE("=====item=====: %d\n", n + 1);
1350 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1351 TRACE(" screen : %d\n", object->visInfo[n].screen);
1352 TRACE(" depth : %u\n", object->visInfo[n].depth);
1353 TRACE(" class : %d\n", object->visInfo[n].class);
1354 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1355 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1356 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1357 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1358 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1359 /* log some extra glx info */
1360 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1361 TRACE(" gl_aux_buffers : %d\n", value);
1362 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1363 TRACE(" gl_buffer_size : %d\n", value);
1364 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1365 TRACE(" gl_red_size : %d\n", value);
1366 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1367 TRACE(" gl_green_size : %d\n", value);
1368 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1369 TRACE(" gl_blue_size : %d\n", value);
1370 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1371 TRACE(" gl_alpha_size : %d\n", value);
1372 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1373 TRACE(" gl_depth_size : %d\n", value);
1374 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1375 TRACE(" gl_stencil_size : %d\n", value);
1377 /* Now choose a similar visual ID*/
1379 #ifdef USE_CONTEXT_MANAGER
1381 /** TODO: use a context mamager **/
1385 IWineD3DSwapChain *implSwapChain;
1386 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1387 /* The first time around we create the context that is shared with all other swapchains and render targets */
1388 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1389 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1392 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1393 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1394 /* and create a new context with the implicit swapchains context as the shared context */
1395 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1396 IWineD3DSwapChain_Release(implSwapChain);
1401 XFree(object->visInfo);
1402 object->visInfo = NULL;
1406 if (!object->glCtx) {
1407 ERR("Failed to create GLX context\n");
1408 return WINED3DERR_NOTAVAILABLE;
1410 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1411 object->win_handle, object->glCtx, object->win, object->visInfo);
1414 /*********************
1415 * Windowed / Fullscreen
1416 *******************/
1419 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1420 * so we should really check to see if there is a fullscreen swapchain already
1421 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1422 **************************************/
1424 if (!*(pPresentationParameters->Windowed)) {
1432 /* Get info on the current display setup */
1434 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1437 /* Change the display settings */
1438 memset(&devmode, 0, sizeof(DEVMODEW));
1439 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1440 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1441 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1442 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1443 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1444 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1446 /* Make popup window, remove caption and borders */
1447 style = GetWindowLongW(object->win_handle, GWL_STYLE);
1448 style &= ~WS_CAPTION;
1449 SetWindowLongW(object->win_handle, GWL_STYLE, style | WS_POPUP);
1450 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1451 *(pPresentationParameters->BackBufferWidth),
1452 *(pPresentationParameters->BackBufferHeight), SWP_FRAMECHANGED);
1454 /* For GetDisplayMode */
1455 This->ddraw_width = devmode.dmPelsWidth;
1456 This->ddraw_height = devmode.dmPelsHeight;
1457 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1459 /* And finally clip mouse to our screen */
1460 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1461 ClipCursor(&clip_rc);
1465 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1466 * then the corresponding dimension of the client area of the hDeviceWindow
1467 * (or the focus window, if hDeviceWindow is NULL) is taken.
1468 **********************/
1470 if (*(pPresentationParameters->Windowed) &&
1471 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1472 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1475 GetClientRect(object->win_handle, &Rect);
1477 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1478 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1479 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1481 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1482 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1483 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1487 /*********************
1488 * finish off parameter initialization
1489 *******************/
1491 /* Put the correct figures in the presentation parameters */
1492 TRACE("Copying across presentation parameters\n");
1493 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1494 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1495 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1496 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1497 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1498 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1499 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1500 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1501 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1502 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1503 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1504 object->presentParms.Flags = *(pPresentationParameters->Flags);
1505 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1506 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1509 /*********************
1510 * Create the back, front and stencil buffers
1511 *******************/
1513 TRACE("calling rendertarget CB\n");
1514 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1516 object->presentParms.BackBufferWidth,
1517 object->presentParms.BackBufferHeight,
1518 object->presentParms.BackBufferFormat,
1519 object->presentParms.MultiSampleType,
1520 object->presentParms.MultiSampleQuality,
1521 TRUE /* Lockable */,
1522 &object->frontBuffer,
1523 NULL /* pShared (always null)*/);
1524 if (object->frontBuffer != NULL)
1525 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1527 if(object->presentParms.BackBufferCount > 0) {
1530 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1531 if(!object->backBuffer) {
1532 ERR("Out of memory\n");
1534 if (object->frontBuffer) {
1535 IUnknown *bufferParent;
1536 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1537 IUnknown_Release(bufferParent); /* once for the get parent */
1538 if (IUnknown_Release(bufferParent) > 0) {
1539 FIXME("(%p) Something's still holding the front buffer\n",This);
1542 HeapFree(GetProcessHeap(), 0, object);
1543 return E_OUTOFMEMORY;
1546 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1547 TRACE("calling rendertarget CB\n");
1548 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1550 object->presentParms.BackBufferWidth,
1551 object->presentParms.BackBufferHeight,
1552 object->presentParms.BackBufferFormat,
1553 object->presentParms.MultiSampleType,
1554 object->presentParms.MultiSampleQuality,
1555 TRUE /* Lockable */,
1556 &object->backBuffer[i],
1557 NULL /* pShared (always null)*/);
1558 if(hr == WINED3D_OK && object->backBuffer[i]) {
1559 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1565 object->backBuffer = NULL;
1568 if (object->backBuffer != NULL) {
1570 glDrawBuffer(GL_BACK);
1571 checkGLcall("glDrawBuffer(GL_BACK)");
1574 /* Single buffering - draw to front buffer */
1576 glDrawBuffer(GL_FRONT);
1577 checkGLcall("glDrawBuffer(GL_FRONT)");
1581 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1582 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1583 TRACE("Creating depth stencil buffer\n");
1584 if (This->depthStencilBuffer == NULL ) {
1585 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1587 object->presentParms.BackBufferWidth,
1588 object->presentParms.BackBufferHeight,
1589 object->presentParms.AutoDepthStencilFormat,
1590 object->presentParms.MultiSampleType,
1591 object->presentParms.MultiSampleQuality,
1592 FALSE /* FIXME: Discard */,
1593 &This->depthStencilBuffer,
1594 NULL /* pShared (always null)*/ );
1595 if (This->depthStencilBuffer != NULL)
1596 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1599 /** TODO: A check on width, height and multisample types
1600 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1601 ****************************/
1602 object->wantsDepthStencilBuffer = TRUE;
1604 object->wantsDepthStencilBuffer = FALSE;
1607 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1610 /*********************
1611 * init the default renderTarget management
1612 *******************/
1613 object->drawable = object->win;
1614 object->render_ctx = object->glCtx;
1616 if (hr == WINED3D_OK) {
1617 /*********************
1618 * Setup some defaults and clear down the buffers
1619 *******************/
1621 /** save current context and drawable **/
1622 oldContext = glXGetCurrentContext();
1623 oldDrawable = glXGetCurrentDrawable();
1625 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1626 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1627 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1629 checkGLcall("glXMakeCurrent");
1631 TRACE("Setting up the screen\n");
1632 /* Clear the screen */
1633 glClearColor(1.0, 0.0, 0.0, 0.0);
1634 checkGLcall("glClearColor");
1637 glClearStencil(0xffff);
1639 checkGLcall("glClear");
1641 glColor3f(1.0, 1.0, 1.0);
1642 checkGLcall("glColor3f");
1644 glEnable(GL_LIGHTING);
1645 checkGLcall("glEnable");
1647 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1648 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1650 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1651 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1653 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1654 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1656 /* switch back to the original context (if there was one)*/
1657 if (This->swapchains) {
1658 /** TODO: restore the context and drawable **/
1659 glXMakeCurrent(object->display, oldDrawable, oldContext);
1662 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1663 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1664 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1665 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1666 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1670 TRACE("Set swapchain to %p\n", object);
1671 } else { /* something went wrong so clean up */
1672 IUnknown* bufferParent;
1673 if (object->frontBuffer) {
1675 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1676 IUnknown_Release(bufferParent); /* once for the get parent */
1677 if (IUnknown_Release(bufferParent) > 0) {
1678 FIXME("(%p) Something's still holding the front buffer\n",This);
1681 if (object->backBuffer) {
1683 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1684 if(object->backBuffer[i]) {
1685 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1686 IUnknown_Release(bufferParent); /* once for the get parent */
1687 if (IUnknown_Release(bufferParent) > 0) {
1688 FIXME("(%p) Something's still holding the back buffer\n",This);
1692 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1693 object->backBuffer = NULL;
1695 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1696 /* Clean up the context */
1697 /* check that we are the current context first (we shouldn't be though!) */
1698 if (object->glCtx != 0) {
1699 if(glXGetCurrentContext() == object->glCtx) {
1700 glXMakeCurrent(object->display, None, NULL);
1702 glXDestroyContext(object->display, object->glCtx);
1704 HeapFree(GetProcessHeap(), 0, object);
1711 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1712 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1714 TRACE("(%p)\n", This);
1716 return This->NumberOfSwapChains;
1719 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1721 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1723 if(iSwapChain < This->NumberOfSwapChains) {
1724 *pSwapChain = This->swapchains[iSwapChain];
1725 IWineD3DSwapChain_AddRef(*pSwapChain);
1726 TRACE("(%p) returning %p\n", This, *pSwapChain);
1729 TRACE("Swapchain out of range\n");
1731 return WINED3DERR_INVALIDCALL;
1736 * Vertex Declaration
1738 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1740 IWineD3DVertexDeclarationImpl *object = NULL;
1741 HRESULT hr = WINED3D_OK;
1742 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1743 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1746 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1751 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1752 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1754 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1755 HRESULT hr = WINED3D_OK;
1756 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1757 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1759 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1761 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1762 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1763 if (pDeclaration != NULL) {
1764 IWineD3DVertexDeclaration *vertexDeclaration;
1765 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1766 if (WINED3D_OK == hr) {
1767 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1768 object->vertexDeclaration = vertexDeclaration;
1770 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1771 IWineD3DVertexShader_Release(*ppVertexShader);
1772 return WINED3DERR_INVALIDCALL;
1776 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1778 if (WINED3D_OK != hr) {
1779 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1780 IWineD3DVertexShader_Release(*ppVertexShader);
1781 return WINED3DERR_INVALIDCALL;
1784 #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. */
1785 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1796 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1798 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1799 HRESULT hr = WINED3D_OK;
1801 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1802 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1803 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1804 if (WINED3D_OK == hr) {
1805 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1807 WARN("(%p) : Failed to create pixel shader\n", This);
1813 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1815 IWineD3DPaletteImpl *object;
1817 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1819 /* Create the new object */
1820 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1822 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1823 return E_OUTOFMEMORY;
1826 object->lpVtbl = &IWineD3DPalette_Vtbl;
1828 object->Flags = Flags;
1829 object->parent = Parent;
1830 object->wineD3DDevice = This;
1831 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1833 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1836 HeapFree( GetProcessHeap(), 0, object);
1837 return E_OUTOFMEMORY;
1840 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1842 IWineD3DPalette_Release((IWineD3DPalette *) object);
1846 *Palette = (IWineD3DPalette *) object;
1851 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1853 IWineD3DSwapChainImpl *swapchain;
1856 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1857 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1859 /* TODO: Test if OpenGL is compiled in and loaded */
1861 /* Initialize the texture unit mapping to a 1:1 mapping */
1862 for(state = 0; state < MAX_SAMPLERS; state++) {
1863 This->texUnitMap[state] = state;
1865 This->oneToOneTexUnitMap = TRUE;
1867 /* Setup the implicit swapchain */
1868 TRACE("Creating implicit swapchain\n");
1869 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
1870 WARN("Failed to create implicit swapchain\n");
1871 return WINED3DERR_INVALIDCALL;
1874 This->NumberOfSwapChains = 1;
1875 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1876 if(!This->swapchains) {
1877 ERR("Out of memory!\n");
1878 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1879 return E_OUTOFMEMORY;
1881 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1883 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1884 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1885 This->render_targets[0] = swapchain->backBuffer[0];
1888 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1889 This->render_targets[0] = swapchain->frontBuffer;
1891 IWineD3DSurface_AddRef(This->render_targets[0]);
1892 /* Depth Stencil support */
1893 This->stencilBufferTarget = This->depthStencilBuffer;
1894 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1895 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1897 if (NULL != This->stencilBufferTarget) {
1898 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1901 /* Set up some starting GL setup */
1904 * Initialize openGL extension related variables
1905 * with Default values
1908 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
1909 /* Setup all the devices defaults */
1910 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1912 IWineD3DImpl_CheckGraphicsMemory();
1916 /* Initialize our list of GLSL programs */
1917 list_init(&This->glsl_shader_progs);
1919 { /* Set a default viewport */
1923 vp.Width = *(pPresentationParameters->BackBufferWidth);
1924 vp.Height = *(pPresentationParameters->BackBufferHeight);
1927 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1930 /* Initialize the current view state */
1931 This->view_ident = 1;
1932 This->last_was_rhw = 0;
1933 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1934 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1936 /* Clear the screen */
1937 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1939 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
1940 * This might create a problem in 2 situations:
1941 * ->The D3D default value is 0, but the opengl default value is something else
1942 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
1944 for(state = 0; state <= STATE_HIGHEST; state++) {
1945 IWineD3DDeviceImpl_MarkStateDirty(This, state);
1948 This->d3d_initialized = TRUE;
1952 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1956 TRACE("(%p)\n", This);
1958 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1960 /* Delete the mouse cursor texture */
1961 if(This->cursorTexture) {
1963 glDeleteTextures(1, &This->cursorTexture);
1965 This->cursorTexture = 0;
1968 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1969 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1972 /* Release the buffers (with sanity checks)*/
1973 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1974 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1975 if(This->depthStencilBuffer != This->stencilBufferTarget)
1976 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1978 This->stencilBufferTarget = NULL;
1980 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1981 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1982 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1984 TRACE("Setting rendertarget to NULL\n");
1985 This->render_targets[0] = NULL;
1987 if (This->depthStencilBuffer) {
1988 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1989 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1991 This->depthStencilBuffer = NULL;
1994 for(i=0; i < This->NumberOfSwapChains; i++) {
1995 TRACE("Releasing the implicit swapchain %d\n", i);
1996 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1997 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2001 HeapFree(GetProcessHeap(), 0, This->swapchains);
2002 This->swapchains = NULL;
2003 This->NumberOfSwapChains = 0;
2005 This->d3d_initialized = FALSE;
2009 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2011 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2013 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2014 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2015 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2018 This->ddraw_fullscreen = fullscreen;
2021 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2026 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2028 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2030 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2031 /* Ignore some modes if a description was passed */
2032 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2033 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2034 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2036 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2038 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2045 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2049 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2052 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2054 /* Resize the screen even without a window:
2055 * The app could have unset it with SetCooperativeLevel, but not called
2056 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2057 * but we don't have any hwnd
2060 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2061 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2062 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2063 devmode.dmPelsWidth = pMode->Width;
2064 devmode.dmPelsHeight = pMode->Height;
2066 devmode.dmDisplayFrequency = pMode->RefreshRate;
2067 if (pMode->RefreshRate != 0) {
2068 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2071 /* Only change the mode if necessary */
2072 if( (This->ddraw_width == pMode->Width) &&
2073 (This->ddraw_height == pMode->Height) &&
2074 (This->ddraw_format == pMode->Format) &&
2075 (pMode->RefreshRate == 0) ) {
2079 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2080 if (ret != DISP_CHANGE_SUCCESSFUL) {
2081 if(devmode.dmDisplayFrequency != 0) {
2082 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2083 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2084 devmode.dmDisplayFrequency = 0;
2085 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2087 if(ret != DISP_CHANGE_SUCCESSFUL) {
2088 return DDERR_INVALIDMODE;
2092 /* Store the new values */
2093 This->ddraw_width = pMode->Width;
2094 This->ddraw_height = pMode->Height;
2095 This->ddraw_format = pMode->Format;
2097 /* Only do this with a window of course */
2098 if(This->ddraw_window)
2099 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2101 /* And finally clip mouse to our screen */
2102 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2103 ClipCursor(&clip_rc);
2108 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2110 *ppD3D= This->wineD3D;
2111 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2112 IWineD3D_AddRef(*ppD3D);
2116 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2117 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2118 * into the video ram as possible and seeing how many fit
2119 * you can also get the correct initial value from nvidia and ATI's driver via X
2120 * texture memory is video memory + AGP memory
2121 *******************/
2122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2123 static BOOL showfixmes = TRUE;
2125 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2126 (wined3d_settings.emulated_textureram/(1024*1024)),
2127 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2130 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2131 (wined3d_settings.emulated_textureram/(1024*1024)),
2132 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2133 /* return simulated texture memory left */
2134 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2142 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2145 /* Update the current state block */
2146 This->updateStateBlock->changed.fvf = TRUE;
2147 This->updateStateBlock->set.fvf = TRUE;
2149 if(This->updateStateBlock->fvf == fvf) {
2150 TRACE("Application is setting the old fvf over, nothing to do\n");
2154 This->updateStateBlock->fvf = fvf;
2155 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2161 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2163 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2164 *pfvf = This->stateBlock->fvf;
2169 * Get / Set Stream Source
2171 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2173 IWineD3DVertexBuffer *oldSrc;
2175 /**TODO: instance and index data, see
2176 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2178 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2181 /* D3d9 only, but shouldn't hurt d3d8 */
2184 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2186 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2187 FIXME("stream index data not supported\n");
2189 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2190 FIXME("stream instance data not supported\n");
2194 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2196 if (StreamNumber >= MAX_STREAMS) {
2197 WARN("Stream out of range %d\n", StreamNumber);
2198 return WINED3DERR_INVALIDCALL;
2201 oldSrc = This->stateBlock->streamSource[StreamNumber];
2202 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2204 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2205 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2207 if(oldSrc == pStreamData &&
2208 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2209 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes &&
2210 This->updateStateBlock->streamFlags[StreamNumber] == streamFlags) {
2211 TRACE("Application is setting the old values over, nothing to do\n");
2215 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2217 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2218 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2220 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2222 /* Handle recording of state blocks */
2223 if (This->isRecordingState) {
2224 TRACE("Recording... not performing anything\n");
2228 /* Same stream object: no action */
2229 if (oldSrc == pStreamData)
2232 /* Need to do a getParent and pass the reffs up */
2233 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2234 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2235 so for now, just count internally */
2236 if (pStreamData != NULL) {
2237 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2238 InterlockedIncrement(&vbImpl->bindCount);
2240 if (oldSrc != NULL) {
2241 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2249 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2254 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2257 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2259 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2260 FIXME("stream index data not supported\n");
2262 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2263 FIXME("stream instance data not supported\n");
2267 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2269 if (StreamNumber >= MAX_STREAMS) {
2270 WARN("Stream out of range %d\n", StreamNumber);
2271 return WINED3DERR_INVALIDCALL;
2273 *pStream = This->stateBlock->streamSource[StreamNumber];
2274 *pStride = This->stateBlock->streamStride[StreamNumber];
2276 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2279 if (*pStream != NULL) {
2280 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2285 /*Should be quite easy, just an extension of vertexdata
2287 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2289 The divider is a bit odd though
2291 VertexOffset = StartVertex / Divider * StreamStride +
2292 VertexIndex / Divider * StreamStride + StreamOffset
2295 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2298 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2299 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2301 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2302 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2303 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2305 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2306 FIXME("Stream indexing not fully supported\n");
2312 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2316 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2318 TRACE("(%p) : returning %d\n", This, *Divider);
2324 * Get / Set & Multiply Transform
2326 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 /* Most of this routine, comments included copied from ddraw tree initially: */
2330 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2332 /* Handle recording of state blocks */
2333 if (This->isRecordingState) {
2334 TRACE("Recording... not performing anything\n");
2335 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2336 This->updateStateBlock->set.transform[d3dts] = TRUE;
2337 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2342 * If the new matrix is the same as the current one,
2343 * we cut off any further processing. this seems to be a reasonable
2344 * optimization because as was noticed, some apps (warcraft3 for example)
2345 * tend towards setting the same matrix repeatedly for some reason.
2347 * From here on we assume that the new matrix is different, wherever it matters.
2349 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2350 TRACE("The app is setting the same matrix over again\n");
2353 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2357 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2358 where ViewMat = Camera space, WorldMat = world space.
2360 In OpenGL, camera and world space is combined into GL_MODELVIEW
2361 matrix. The Projection matrix stay projection matrix.
2364 /* Capture the times we can just ignore the change for now */
2365 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2366 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2367 /* Handled by the state manager */
2370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2374 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2376 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2377 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2381 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2382 WINED3DMATRIX *mat = NULL;
2385 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2386 * below means it will be recorded in a state block change, but it
2387 * works regardless where it is recorded.
2388 * If this is found to be wrong, change to StateBlock.
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2393 if (State < HIGHEST_TRANSFORMSTATE)
2395 mat = &This->updateStateBlock->transforms[State];
2397 FIXME("Unhandled transform state!!\n");
2400 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2402 /* Apply change via set transform - will reapply to eg. lights this way */
2403 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2409 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2410 you can reference any indexes you want as long as that number max are enabled at any
2411 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2412 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2413 but when recording, just build a chain pretty much of commands to be replayed. */
2415 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2417 PLIGHTINFOEL *object, *temp;
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2420 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2422 /* If recording state block, just add to end of lights chain */
2423 if (This->isRecordingState) {
2424 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2425 if (NULL == object) {
2426 return WINED3DERR_OUTOFVIDEOMEMORY;
2428 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2429 object->OriginalIndex = Index;
2430 object->glIndex = -1;
2431 object->changed = TRUE;
2433 /* Add to the END of the chain of lights changes to be replayed */
2434 if (This->updateStateBlock->lights == NULL) {
2435 This->updateStateBlock->lights = object;
2437 temp = This->updateStateBlock->lights;
2438 while (temp->next != NULL) temp=temp->next;
2439 temp->next = object;
2441 TRACE("Recording... not performing anything more\n");
2445 /* Ok, not recording any longer so do real work */
2446 object = This->stateBlock->lights;
2447 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2449 /* If we didn't find it in the list of lights, time to add it */
2450 if (object == NULL) {
2451 PLIGHTINFOEL *insertAt,*prevPos;
2453 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2454 if (NULL == object) {
2455 return WINED3DERR_OUTOFVIDEOMEMORY;
2457 object->OriginalIndex = Index;
2458 object->glIndex = -1;
2460 /* Add it to the front of list with the idea that lights will be changed as needed
2461 BUT after any lights currently assigned GL indexes */
2462 insertAt = This->stateBlock->lights;
2464 while (insertAt != NULL && insertAt->glIndex != -1) {
2466 insertAt = insertAt->next;
2469 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2470 This->stateBlock->lights = object;
2471 } else if (insertAt == NULL) { /* End of list */
2472 prevPos->next = object;
2473 object->prev = prevPos;
2474 } else { /* Middle of chain */
2475 if (prevPos == NULL) {
2476 This->stateBlock->lights = object;
2478 prevPos->next = object;
2480 object->prev = prevPos;
2481 object->next = insertAt;
2482 insertAt->prev = object;
2486 /* Initialize the object */
2487 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,
2488 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2489 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2490 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2491 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2492 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2493 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2495 /* Save away the information */
2496 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2498 switch (pLight->Type) {
2499 case WINED3DLIGHT_POINT:
2501 object->lightPosn[0] = pLight->Position.x;
2502 object->lightPosn[1] = pLight->Position.y;
2503 object->lightPosn[2] = pLight->Position.z;
2504 object->lightPosn[3] = 1.0f;
2505 object->cutoff = 180.0f;
2509 case WINED3DLIGHT_DIRECTIONAL:
2511 object->lightPosn[0] = -pLight->Direction.x;
2512 object->lightPosn[1] = -pLight->Direction.y;
2513 object->lightPosn[2] = -pLight->Direction.z;
2514 object->lightPosn[3] = 0.0;
2515 object->exponent = 0.0f;
2516 object->cutoff = 180.0f;
2519 case WINED3DLIGHT_SPOT:
2521 object->lightPosn[0] = pLight->Position.x;
2522 object->lightPosn[1] = pLight->Position.y;
2523 object->lightPosn[2] = pLight->Position.z;
2524 object->lightPosn[3] = 1.0;
2527 object->lightDirn[0] = pLight->Direction.x;
2528 object->lightDirn[1] = pLight->Direction.y;
2529 object->lightDirn[2] = pLight->Direction.z;
2530 object->lightDirn[3] = 1.0;
2533 * opengl-ish and d3d-ish spot lights use too different models for the
2534 * light "intensity" as a function of the angle towards the main light direction,
2535 * so we only can approximate very roughly.
2536 * however spot lights are rather rarely used in games (if ever used at all).
2537 * furthermore if still used, probably nobody pays attention to such details.
2539 if (pLight->Falloff == 0) {
2542 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2544 if (rho < 0.0001) rho = 0.0001f;
2545 object->exponent = -0.3/log(cos(rho/2));
2546 if (object->exponent > 128.0) {
2547 object->exponent = 128.0;
2549 object->cutoff = pLight->Phi*90/M_PI;
2555 FIXME("Unrecognized light type %d\n", pLight->Type);
2558 /* Update the live definitions if the light is currently assigned a glIndex */
2559 if (object->glIndex != -1) {
2560 setup_light(iface, object->glIndex, object);
2565 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2566 PLIGHTINFOEL *lightInfo = NULL;
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2570 /* Locate the light in the live lights */
2571 lightInfo = This->stateBlock->lights;
2572 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2574 if (lightInfo == NULL) {
2575 TRACE("Light information requested but light not defined\n");
2576 return WINED3DERR_INVALIDCALL;
2579 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2584 * Get / Set Light Enable
2585 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2587 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2588 PLIGHTINFOEL *lightInfo = NULL;
2589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2590 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2592 /* Tests show true = 128...not clear why */
2594 Enable = Enable? 128: 0;
2596 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2597 if (This->isRecordingState) {
2598 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2599 if (NULL == lightInfo) {
2600 return WINED3DERR_OUTOFVIDEOMEMORY;
2602 lightInfo->OriginalIndex = Index;
2603 lightInfo->glIndex = -1;
2604 lightInfo->enabledChanged = TRUE;
2605 lightInfo->lightEnabled = Enable;
2607 /* Add to the END of the chain of lights changes to be replayed */
2608 if (This->updateStateBlock->lights == NULL) {
2609 This->updateStateBlock->lights = lightInfo;
2611 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2612 while (temp->next != NULL) temp=temp->next;
2613 temp->next = lightInfo;
2615 TRACE("Recording... not performing anything more\n");
2619 /* Not recording... So, locate the light in the live lights */
2620 lightInfo = This->stateBlock->lights;
2621 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2623 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2624 if (lightInfo == NULL) {
2626 TRACE("Light enabled requested but light not defined, so defining one!\n");
2627 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2629 /* Search for it again! Should be fairly quick as near head of list */
2630 lightInfo = This->stateBlock->lights;
2631 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2632 if (lightInfo == NULL) {
2633 FIXME("Adding default lights has failed dismally\n");
2634 return WINED3DERR_INVALIDCALL;
2638 /* OK, we now have a light... */
2641 /* If we are disabling it, check it was enabled, and
2642 still only do something if it has assigned a glIndex (which it should have!) */
2643 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2644 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2646 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2647 checkGLcall("glDisable GL_LIGHT0+Index");
2650 TRACE("Nothing to do as light was not enabled\n");
2652 lightInfo->lightEnabled = Enable;
2655 /* We are enabling it. If it is enabled, it's really simple */
2656 if (lightInfo->lightEnabled) {
2658 TRACE("Nothing to do as light was enabled\n");
2660 /* If it already has a glIndex, it's still simple */
2661 } else if (lightInfo->glIndex != -1) {
2662 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2663 lightInfo->lightEnabled = Enable;
2665 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2666 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2669 /* Otherwise got to find space - lights are ordered gl indexes first */
2671 PLIGHTINFOEL *bsf = NULL;
2672 PLIGHTINFOEL *pos = This->stateBlock->lights;
2673 PLIGHTINFOEL *prev = NULL;
2677 /* Try to minimize changes as much as possible */
2678 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2680 /* Try to remember which index can be replaced if necessary */
2681 if (bsf==NULL && !pos->lightEnabled) {
2682 /* Found a light we can replace, save as best replacement */
2686 /* Step to next space */
2692 /* If we have too many active lights, fail the call */
2693 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2694 FIXME("Program requests too many concurrent lights\n");
2695 return WINED3DERR_INVALIDCALL;
2697 /* If we have allocated all lights, but not all are enabled,
2698 reuse one which is not enabled */
2699 } else if (Index == This->maxConcurrentLights) {
2700 /* use bsf - Simply swap the new light and the BSF one */
2701 PLIGHTINFOEL *bsfNext = bsf->next;
2702 PLIGHTINFOEL *bsfPrev = bsf->prev;
2705 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2706 if (bsf->prev != NULL) {
2707 bsf->prev->next = lightInfo;
2709 This->stateBlock->lights = lightInfo;
2712 /* If not side by side, lots of chains to update */
2713 if (bsf->next != lightInfo) {
2714 lightInfo->prev->next = bsf;
2715 bsf->next->prev = lightInfo;
2716 bsf->next = lightInfo->next;
2717 bsf->prev = lightInfo->prev;
2718 lightInfo->next = bsfNext;
2719 lightInfo->prev = bsfPrev;
2723 bsf->prev = lightInfo;
2724 bsf->next = lightInfo->next;
2725 lightInfo->next = bsf;
2726 lightInfo->prev = bsfPrev;
2731 glIndex = bsf->glIndex;
2733 lightInfo->glIndex = glIndex;
2734 lightInfo->lightEnabled = Enable;
2736 /* Finally set up the light in gl itself */
2737 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2739 setup_light(iface, glIndex, lightInfo);
2740 glEnable(GL_LIGHT0 + glIndex);
2741 checkGLcall("glEnable GL_LIGHT0 new setup");
2744 /* If we reached the end of the allocated lights, with space in the
2745 gl lights, setup a new light */
2746 } else if (pos->glIndex == -1) {
2748 /* We reached the end of the allocated gl lights, so already
2749 know the index of the next one! */
2751 lightInfo->glIndex = glIndex;
2752 lightInfo->lightEnabled = Enable;
2754 /* In an ideal world, it's already in the right place */
2755 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2756 /* No need to move it */
2758 /* Remove this light from the list */
2759 lightInfo->prev->next = lightInfo->next;
2760 if (lightInfo->next != NULL) {
2761 lightInfo->next->prev = lightInfo->prev;
2764 /* Add in at appropriate place (inbetween prev and pos) */
2765 lightInfo->prev = prev;
2766 lightInfo->next = pos;
2768 This->stateBlock->lights = lightInfo;
2770 prev->next = lightInfo;
2773 pos->prev = lightInfo;
2777 /* Finally set up the light in gl itself */
2778 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
2780 setup_light(iface, glIndex, lightInfo);
2781 glEnable(GL_LIGHT0 + glIndex);
2782 checkGLcall("glEnable GL_LIGHT0 new setup");
2791 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2793 PLIGHTINFOEL *lightInfo = NULL;
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2795 TRACE("(%p) : for idx(%d)\n", This, Index);
2797 /* Locate the light in the live lights */
2798 lightInfo = This->stateBlock->lights;
2799 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2801 if (lightInfo == NULL) {
2802 TRACE("Light enabled state requested but light not defined\n");
2803 return WINED3DERR_INVALIDCALL;
2805 *pEnable = lightInfo->lightEnabled;
2810 * Get / Set Clip Planes
2812 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2816 /* Validate Index */
2817 if (Index >= GL_LIMITS(clipplanes)) {
2818 TRACE("Application has requested clipplane this device doesn't support\n");
2819 return WINED3DERR_INVALIDCALL;
2822 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2823 This->updateStateBlock->set.clipplane[Index] = TRUE;
2824 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2825 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2826 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2827 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2829 /* Handle recording of state blocks */
2830 if (This->isRecordingState) {
2831 TRACE("Recording... not performing anything\n");
2839 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2840 glMatrixMode(GL_MODELVIEW);
2842 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2844 TRACE("Clipplane [%f,%f,%f,%f]\n",
2845 This->updateStateBlock->clipplane[Index][0],
2846 This->updateStateBlock->clipplane[Index][1],
2847 This->updateStateBlock->clipplane[Index][2],
2848 This->updateStateBlock->clipplane[Index][3]);
2849 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2850 checkGLcall("glClipPlane");
2858 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 TRACE("(%p) : for idx %d\n", This, Index);
2862 /* Validate Index */
2863 if (Index >= GL_LIMITS(clipplanes)) {
2864 TRACE("Application has requested clipplane this device doesn't support\n");
2865 return WINED3DERR_INVALIDCALL;
2868 pPlane[0] = This->stateBlock->clipplane[Index][0];
2869 pPlane[1] = This->stateBlock->clipplane[Index][1];
2870 pPlane[2] = This->stateBlock->clipplane[Index][2];
2871 pPlane[3] = This->stateBlock->clipplane[Index][3];
2876 * Get / Set Clip Plane Status
2877 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2879 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 FIXME("(%p) : stub\n", This);
2882 if (NULL == pClipStatus) {
2883 return WINED3DERR_INVALIDCALL;
2885 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2886 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2890 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2892 FIXME("(%p) : stub\n", This);
2893 if (NULL == pClipStatus) {
2894 return WINED3DERR_INVALIDCALL;
2896 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2897 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2902 * Get / Set Material
2904 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 This->updateStateBlock->changed.material = TRUE;
2908 This->updateStateBlock->set.material = TRUE;
2909 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2911 /* Handle recording of state blocks */
2912 if (This->isRecordingState) {
2913 TRACE("Recording... not performing anything\n");
2918 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2919 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2920 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2921 pMaterial->Ambient.b, pMaterial->Ambient.a);
2922 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2923 pMaterial->Specular.b, pMaterial->Specular.a);
2924 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2925 pMaterial->Emissive.b, pMaterial->Emissive.a);
2926 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2928 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2929 checkGLcall("glMaterialfv(GL_AMBIENT)");
2930 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2931 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2933 /* Only change material color if specular is enabled, otherwise it is set to black */
2934 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2935 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2936 checkGLcall("glMaterialfv(GL_SPECULAR");
2938 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2939 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2940 checkGLcall("glMaterialfv(GL_SPECULAR");
2942 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2943 checkGLcall("glMaterialfv(GL_EMISSION)");
2944 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2945 checkGLcall("glMaterialf(GL_SHININESS");
2951 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2954 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2955 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2956 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2957 pMaterial->Ambient.b, pMaterial->Ambient.a);
2958 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2959 pMaterial->Specular.b, pMaterial->Specular.a);
2960 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2961 pMaterial->Emissive.b, pMaterial->Emissive.a);
2962 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2970 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2971 UINT BaseVertexIndex) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 IWineD3DIndexBuffer *oldIdxs;
2974 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2976 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2977 oldIdxs = This->updateStateBlock->pIndexData;
2979 This->updateStateBlock->changed.indices = TRUE;
2980 This->updateStateBlock->set.indices = TRUE;
2981 This->updateStateBlock->pIndexData = pIndexData;
2982 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2984 /* Handle recording of state blocks */
2985 if (This->isRecordingState) {
2986 TRACE("Recording... not performing anything\n");
2990 /* So far only the base vertex index is tracked */
2991 if(BaseVertexIndex != oldBaseIndex) {
2992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2997 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 *ppIndexData = This->stateBlock->pIndexData;
3002 /* up ref count on ppindexdata */
3004 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3005 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3006 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3008 TRACE("(%p) No index data set\n", This);
3010 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3015 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3016 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 TRACE("(%p)->(%d)\n", This, BaseIndex);
3020 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3021 TRACE("Application is setting the old value over, nothing to do\n");
3025 This->updateStateBlock->baseVertexIndex = BaseIndex;
3027 if (This->isRecordingState) {
3028 TRACE("Recording... not performing anything\n");
3031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3036 * Get / Set Viewports
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 TRACE("(%p)\n", This);
3042 This->updateStateBlock->changed.viewport = TRUE;
3043 This->updateStateBlock->set.viewport = TRUE;
3044 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3046 /* Handle recording of state blocks */
3047 if (This->isRecordingState) {
3048 TRACE("Recording... not performing anything\n");
3052 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3053 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3060 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3062 TRACE("(%p)\n", This);
3063 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3068 * Get / Set Render States
3069 * TODO: Verify against dx9 definitions
3071 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 DWORD oldValue = This->stateBlock->renderState[State];
3076 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3078 This->updateStateBlock->changed.renderState[State] = TRUE;
3079 This->updateStateBlock->set.renderState[State] = TRUE;
3080 This->updateStateBlock->renderState[State] = Value;
3082 /* Handle recording of state blocks */
3083 if (This->isRecordingState) {
3084 TRACE("Recording... not performing anything\n");
3088 /* Compared here and not before the assignment to allow proper stateblock recording */
3089 if(Value == oldValue) {
3090 TRACE("Application is setting the old value over, nothing to do\n");
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3098 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3101 *pValue = This->stateBlock->renderState[State];
3106 * Get / Set Sampler States
3107 * TODO: Verify against dx9 definitions
3110 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3115 * SetSampler is designed to allow for more than the standard up to 8 textures
3116 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3117 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3119 * http://developer.nvidia.com/object/General_FAQ.html#t6
3121 * There are two new settings for GForce
3123 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3124 * and the texture one:
3125 * GL_MAX_TEXTURE_COORDS_ARB.
3126 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3128 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
3129 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3130 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3131 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3132 return WINED3DERR_INVALIDCALL;
3135 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3136 debug_d3dsamplerstate(Type), Type, Value);
3137 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3138 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3139 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3141 /* Handle recording of state blocks */
3142 if (This->isRecordingState) {
3143 TRACE("Recording... not performing anything\n");
3147 if(oldValue == Value) {
3148 TRACE("Application is setting the old value over, nothing to do\n");
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3157 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 /** TODO: check that sampler is in range **/
3160 *Value = This->stateBlock->samplerState[Sampler][Type];
3161 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3166 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 This->updateStateBlock->set.scissorRect = TRUE;
3172 This->updateStateBlock->changed.scissorRect = TRUE;
3173 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
3175 if(This->isRecordingState) {
3176 TRACE("Recording... not performing anything\n");
3180 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3181 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3182 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3184 winHeight = windowRect.bottom - windowRect.top;
3185 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3186 pRect->right - pRect->left, pRect->bottom - pRect->top);
3188 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3189 checkGLcall("glScissor");
3195 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3199 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3203 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3205 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3207 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3209 This->updateStateBlock->vertexDecl = pDecl;
3210 This->updateStateBlock->changed.vertexDecl = TRUE;
3211 This->updateStateBlock->set.vertexDecl = TRUE;
3213 if (This->isRecordingState) {
3214 TRACE("Recording... not performing anything\n");
3216 } else if(pDecl == oldDecl) {
3217 /* Checked after the assignment to allow proper stateblock recording */
3218 TRACE("Application is setting the old declaration over, nothing to do\n");
3222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3231 *ppDecl = This->stateBlock->vertexDecl;
3232 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3236 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3240 This->updateStateBlock->vertexShader = pShader;
3241 This->updateStateBlock->changed.vertexShader = TRUE;
3242 This->updateStateBlock->set.vertexShader = TRUE;
3244 if (This->isRecordingState) {
3245 TRACE("Recording... not performing anything\n");
3247 } else if(oldShader == pShader) {
3248 /* Checked here to allow proper stateblock recording */
3249 TRACE("App is setting the old shader over, nothing to do\n");
3253 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 if (NULL == ppShader) {
3264 return WINED3DERR_INVALIDCALL;
3266 *ppShader = This->stateBlock->vertexShader;
3267 if( NULL != *ppShader)
3268 IWineD3DVertexShader_AddRef(*ppShader);
3270 TRACE("(%p) : returning %p\n", This, *ppShader);
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3275 IWineD3DDevice *iface,
3277 CONST BOOL *srcData,
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3281 int i, cnt = min(count, MAX_CONST_B - start);
3283 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3284 iface, srcData, start, count);
3286 if (srcData == NULL || cnt < 0)
3287 return WINED3DERR_INVALIDCALL;
3289 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3290 for (i = 0; i < cnt; i++)
3291 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3293 for (i = start; i < cnt + start; ++i) {
3294 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3295 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3303 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3304 IWineD3DDevice *iface,
3309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3310 int cnt = min(count, MAX_CONST_B - start);
3312 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3313 iface, dstData, start, count);
3315 if (dstData == NULL || cnt < 0)
3316 return WINED3DERR_INVALIDCALL;
3318 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3322 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3323 IWineD3DDevice *iface,
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 int i, cnt = min(count, MAX_CONST_I - start);
3331 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3332 iface, srcData, start, count);
3334 if (srcData == NULL || cnt < 0)
3335 return WINED3DERR_INVALIDCALL;
3337 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3338 for (i = 0; i < cnt; i++)
3339 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3340 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3342 for (i = start; i < cnt + start; ++i) {
3343 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3344 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3353 IWineD3DDevice *iface,
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 int cnt = min(count, MAX_CONST_I - start);
3361 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3362 iface, dstData, start, count);
3364 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3365 return WINED3DERR_INVALIDCALL;
3367 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3371 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3372 IWineD3DDevice *iface,
3374 CONST float *srcData,
3377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3378 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3380 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3381 iface, srcData, start, count);
3383 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3384 return WINED3DERR_INVALIDCALL;
3386 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3387 for (i = 0; i < cnt; i++)
3388 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3389 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3391 for (i = start; i < cnt + start; ++i) {
3392 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3393 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3395 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3396 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3398 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3406 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3407 IWineD3DDevice *iface,
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3413 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3415 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3416 iface, dstData, start, count);
3418 if (dstData == NULL || cnt < 0)
3419 return WINED3DERR_INVALIDCALL;
3421 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3425 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3427 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3432 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3434 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3435 * it is never called.
3438 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3439 * that would be really messy and require shader recompilation
3440 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3441 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3442 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3443 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3445 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3446 if(This->oneToOneTexUnitMap) {
3447 TRACE("Not touching 1:1 map\n");
3450 TRACE("Restoring 1:1 texture unit mapping\n");
3451 /* Restore a 1:1 mapping */
3452 for(i = 0; i < MAX_SAMPLERS; i++) {
3453 if(This->texUnitMap[i] != i) {
3454 This->texUnitMap[i] = i;
3455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3456 markTextureStagesDirty(This, i);
3459 This->oneToOneTexUnitMap = TRUE;
3462 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3463 * First, see if we can succeed at all
3466 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3467 if(This->stateBlock->textures[i] == NULL) tex++;
3470 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3471 FIXME("Too many bound textures to support the combiner settings\n");
3475 /* Now work out the mapping */
3477 This->oneToOneTexUnitMap = FALSE;
3478 WARN("Non 1:1 mapping UNTESTED!\n");
3479 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3480 /* Skip NULL textures */
3481 if (!This->stateBlock->textures[i]) {
3482 /* Map to -1, so the check below doesn't fail if a non-NULL
3483 * texture is set on this stage */
3484 TRACE("Mapping texture stage %d to -1\n", i);
3485 This->texUnitMap[i] = -1;
3490 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3491 if(This->texUnitMap[i] != tex) {
3492 This->texUnitMap[i] = tex;
3493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3494 markTextureStagesDirty(This, i);
3502 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3505 This->updateStateBlock->pixelShader = pShader;
3506 This->updateStateBlock->changed.pixelShader = TRUE;
3507 This->updateStateBlock->set.pixelShader = TRUE;
3509 /* Handle recording of state blocks */
3510 if (This->isRecordingState) {
3511 TRACE("Recording... not performing anything\n");
3514 if (This->isRecordingState) {
3515 TRACE("Recording... not performing anything\n");
3519 if(pShader == oldShader) {
3520 TRACE("App is setting the old pixel shader over, nothing to do\n");
3524 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3525 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3527 /* Rebuild the texture unit mapping if nvrc's are supported */
3528 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3529 IWineD3DDeviceImpl_FindTexUnitMap(This);
3535 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3538 if (NULL == ppShader) {
3539 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3540 return WINED3DERR_INVALIDCALL;
3543 *ppShader = This->stateBlock->pixelShader;
3544 if (NULL != *ppShader) {
3545 IWineD3DPixelShader_AddRef(*ppShader);
3547 TRACE("(%p) : returning %p\n", This, *ppShader);
3551 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3552 IWineD3DDevice *iface,
3554 CONST BOOL *srcData,
3557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3558 int i, cnt = min(count, MAX_CONST_B - start);
3560 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3561 iface, srcData, start, count);
3563 if (srcData == NULL || cnt < 0)
3564 return WINED3DERR_INVALIDCALL;
3566 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3567 for (i = 0; i < cnt; i++)
3568 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3570 for (i = start; i < cnt + start; ++i) {
3571 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3572 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3580 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3581 IWineD3DDevice *iface,
3586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3587 int cnt = min(count, MAX_CONST_B - start);
3589 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3590 iface, dstData, start, count);
3592 if (dstData == NULL || cnt < 0)
3593 return WINED3DERR_INVALIDCALL;
3595 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3599 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3600 IWineD3DDevice *iface,
3605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3606 int i, cnt = min(count, MAX_CONST_I - start);
3608 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3609 iface, srcData, start, count);
3611 if (srcData == NULL || cnt < 0)
3612 return WINED3DERR_INVALIDCALL;
3614 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3615 for (i = 0; i < cnt; i++)
3616 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3617 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3619 for (i = start; i < cnt + start; ++i) {
3620 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3621 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3629 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3630 IWineD3DDevice *iface,
3635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636 int cnt = min(count, MAX_CONST_I - start);
3638 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3639 iface, dstData, start, count);
3641 if (dstData == NULL || cnt < 0)
3642 return WINED3DERR_INVALIDCALL;
3644 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3648 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3649 IWineD3DDevice *iface,
3651 CONST float *srcData,
3654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3655 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3657 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3658 iface, srcData, start, count);
3660 if (srcData == NULL || cnt < 0)
3661 return WINED3DERR_INVALIDCALL;
3663 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3664 for (i = 0; i < cnt; i++)
3665 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3666 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3668 for (i = start; i < cnt + start; ++i) {
3669 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3670 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3672 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3673 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3675 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3683 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3684 IWineD3DDevice *iface,
3689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3690 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3692 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3693 iface, dstData, start, count);
3695 if (dstData == NULL || cnt < 0)
3696 return WINED3DERR_INVALIDCALL;
3698 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3702 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3704 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3705 char *dest_ptr, *dest_conv = NULL;
3707 DWORD DestFVF = dest->fvf;
3709 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3713 if (SrcFVF & WINED3DFVF_NORMAL) {
3714 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3717 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3718 ERR("Source has no position mask\n");
3719 return WINED3DERR_INVALIDCALL;
3722 /* We might access VBOs from this code, so hold the lock */
3725 if (dest->resource.allocatedMemory == NULL) {
3726 /* This may happen if we do direct locking into a vbo. Unlikely,
3727 * but theoretically possible(ddraw processvertices test)
3729 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3730 if(!dest->resource.allocatedMemory) {
3732 ERR("Out of memory\n");
3733 return E_OUTOFMEMORY;
3737 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3738 checkGLcall("glBindBufferARB");
3739 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3741 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3743 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3744 checkGLcall("glUnmapBufferARB");
3748 /* Get a pointer into the destination vbo(create one if none exists) and
3749 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3751 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3756 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3757 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3759 ERR("glMapBuffer failed\n");
3760 /* Continue without storing converted vertices */
3765 * a) WINED3DRS_CLIPPING is enabled
3766 * b) WINED3DVOP_CLIP is passed
3768 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3769 static BOOL warned = FALSE;
3771 * The clipping code is not quite correct. Some things need
3772 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3773 * so disable clipping for now.
3774 * (The graphics in Half-Life are broken, and my processvertices
3775 * test crashes with IDirect3DDevice3)
3781 FIXME("Clipping is broken and disabled for now\n");
3783 } else doClip = FALSE;
3784 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3786 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3789 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3792 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3793 WINED3DTS_PROJECTION,
3795 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3796 WINED3DTS_WORLDMATRIX(0),
3799 TRACE("View mat:\n");
3800 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);
3801 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);
3802 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);
3803 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);
3805 TRACE("Proj mat:\n");
3806 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);
3807 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);
3808 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);
3809 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);
3811 TRACE("World mat:\n");
3812 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);
3813 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);
3814 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);
3815 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);
3817 /* Get the viewport */
3818 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3819 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3820 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3822 multiply_matrix(&mat,&view_mat,&world_mat);
3823 multiply_matrix(&mat,&proj_mat,&mat);
3825 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3827 for (i = 0; i < dwCount; i+= 1) {
3828 unsigned int tex_index;
3830 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3831 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3832 /* The position first */
3834 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3836 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3838 /* Multiplication with world, view and projection matrix */
3839 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);
3840 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);
3841 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);
3842 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);
3844 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3846 /* WARNING: The following things are taken from d3d7 and were not yet checked
3847 * against d3d8 or d3d9!
3850 /* Clipping conditions: From
3851 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3853 * A vertex is clipped if it does not match the following requirements
3857 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3859 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3860 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3865 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3866 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3869 /* "Normal" viewport transformation (not clipped)
3870 * 1) The values are divided by rhw
3871 * 2) The y axis is negative, so multiply it with -1
3872 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3873 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3874 * 4) Multiply x with Width/2 and add Width/2
3875 * 5) The same for the height
3876 * 6) Add the viewpoint X and Y to the 2D coordinates and
3877 * The minimum Z value to z
3878 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3880 * Well, basically it's simply a linear transformation into viewport
3892 z *= vp.MaxZ - vp.MinZ;
3894 x += vp.Width / 2 + vp.X;
3895 y += vp.Height / 2 + vp.Y;
3900 /* That vertex got clipped
3901 * Contrary to OpenGL it is not dropped completely, it just
3902 * undergoes a different calculation.
3904 TRACE("Vertex got clipped\n");
3911 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3912 * outside of the main vertex buffer memory. That needs some more
3917 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3920 ( (float *) dest_ptr)[0] = x;
3921 ( (float *) dest_ptr)[1] = y;
3922 ( (float *) dest_ptr)[2] = z;
3923 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3925 dest_ptr += 3 * sizeof(float);
3927 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3928 dest_ptr += sizeof(float);
3933 ( (float *) dest_conv)[0] = x * w;
3934 ( (float *) dest_conv)[1] = y * w;
3935 ( (float *) dest_conv)[2] = z * w;
3936 ( (float *) dest_conv)[3] = w;
3938 dest_conv += 3 * sizeof(float);
3940 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3941 dest_conv += sizeof(float);
3945 if (DestFVF & WINED3DFVF_PSIZE) {
3946 dest_ptr += sizeof(DWORD);
3947 if(dest_conv) dest_conv += sizeof(DWORD);
3949 if (DestFVF & WINED3DFVF_NORMAL) {
3951 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3952 /* AFAIK this should go into the lighting information */
3953 FIXME("Didn't expect the destination to have a normal\n");
3954 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3956 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3960 if (DestFVF & WINED3DFVF_DIFFUSE) {
3962 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3964 static BOOL warned = FALSE;
3967 ERR("No diffuse color in source, but destination has one\n");
3971 *( (DWORD *) dest_ptr) = 0xffffffff;
3972 dest_ptr += sizeof(DWORD);
3975 *( (DWORD *) dest_conv) = 0xffffffff;
3976 dest_conv += sizeof(DWORD);
3980 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3982 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3983 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3984 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3985 dest_conv += sizeof(DWORD);
3990 if (DestFVF & WINED3DFVF_SPECULAR) {
3991 /* What's the color value in the feedback buffer? */
3993 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3995 static BOOL warned = FALSE;
3998 ERR("No specular color in source, but destination has one\n");
4002 *( (DWORD *) dest_ptr) = 0xFF000000;
4003 dest_ptr += sizeof(DWORD);
4006 *( (DWORD *) dest_conv) = 0xFF000000;
4007 dest_conv += sizeof(DWORD);
4011 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4013 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4014 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4015 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4016 dest_conv += sizeof(DWORD);
4021 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4023 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4024 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4026 ERR("No source texture, but destination requests one\n");
4027 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4028 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4031 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4033 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4040 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4041 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4048 #undef copy_and_next
4050 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4053 WineDirect3DVertexStridedData strided;
4054 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4057 WARN("NULL source vertex buffer\n");
4058 return WINED3DERR_INVALIDCALL;
4060 /* We don't need the source vbo because this buffer is only used as
4061 * a source for ProcessVertices. Avoid wasting resources by converting the
4062 * buffer and loading the VBO
4065 TRACE("Releasing the source vbo, it won't be needed\n");
4067 if(!SrcImpl->resource.allocatedMemory) {
4068 /* Rescue the data from the buffer */
4070 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4071 if(!SrcImpl->resource.allocatedMemory) {
4072 ERR("Out of memory\n");
4073 return E_OUTOFMEMORY;
4077 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4078 checkGLcall("glBindBufferARB");
4080 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4082 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4085 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4086 checkGLcall("glUnmapBufferARB");
4091 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4092 checkGLcall("glBindBufferARB");
4093 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4094 checkGLcall("glDeleteBuffersARB");
4100 memset(&strided, 0, sizeof(strided));
4101 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
4103 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4107 * Get / Set Texture Stage States
4108 * TODO: Verify against dx9 definitions
4110 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4112 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4114 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4116 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4118 /* Reject invalid texture units */
4119 if (Stage >= GL_LIMITS(texture_stages)) {
4120 TRACE("Attempt to access invalid texture rejected\n");
4121 return WINED3DERR_INVALIDCALL;
4124 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4125 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4126 This->updateStateBlock->textureState[Stage][Type] = Value;
4128 if (This->isRecordingState) {
4129 TRACE("Recording... not performing anything\n");
4133 /* Checked after the assignments to allow proper stateblock recording */
4134 if(oldValue == Value) {
4135 TRACE("App is setting the old value over, nothing to do\n");
4139 if(Stage > This->stateBlock->lowest_disabled_stage &&
4140 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4141 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4142 * Changes in other states are important on disabled stages too
4147 if(Type == WINED3DTSS_COLOROP) {
4150 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4151 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4152 * they have to be disabled
4154 * The current stage is dirtified below.
4156 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4157 TRACE("Additionally dirtifying stage %d\n", i);
4158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4160 This->stateBlock->lowest_disabled_stage = Stage;
4161 TRACE("New lowest disabled: %d\n", Stage);
4162 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4163 /* Previously disabled stage enabled. Stages above it may need enabling
4164 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4165 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4167 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4170 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4171 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4174 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4177 This->stateBlock->lowest_disabled_stage = i;
4178 TRACE("New lowest disabled: %d\n", i);
4180 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4181 /* TODO: Built a stage -> texture unit mapping for register combiners */
4185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4187 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4188 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4189 * will call FindTexUnitMap too.
4191 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4192 IWineD3DDeviceImpl_FindTexUnitMap(This);
4197 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4199 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4200 *pValue = This->updateStateBlock->textureState[Stage][Type];
4207 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4210 IWineD3DBaseTexture *oldTexture;
4212 oldTexture = This->updateStateBlock->textures[Stage];
4213 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4215 #if 0 /* TODO: check so vertex textures */
4216 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4217 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4222 /* Reject invalid texture units */
4223 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4224 WARN("Attempt to access invalid texture rejected\n");
4225 return WINED3DERR_INVALIDCALL;
4228 if(pTexture != NULL) {
4229 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4231 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4232 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4233 return WINED3DERR_INVALIDCALL;
4235 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4238 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4239 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4241 This->updateStateBlock->set.textures[Stage] = TRUE;
4242 This->updateStateBlock->changed.textures[Stage] = TRUE;
4243 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4244 This->updateStateBlock->textures[Stage] = pTexture;
4246 /* Handle recording of state blocks */
4247 if (This->isRecordingState) {
4248 TRACE("Recording... not performing anything\n");
4252 if(oldTexture == pTexture) {
4253 TRACE("App is setting the same texture again, nothing to do\n");
4257 /** NOTE: MSDN says that setTexture increases the reference count,
4258 * and the the application nust set the texture back to null (or have a leaky application),
4259 * This means we should pass the refcount up to the parent
4260 *******************************/
4261 if (NULL != This->updateStateBlock->textures[Stage]) {
4262 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4263 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4265 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4266 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4267 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4268 * so the COLOROP and ALPHAOP have to be dirtified.
4270 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4273 if(bindCount == 1) {
4274 new->baseTexture.sampler = Stage;
4276 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4280 if (NULL != oldTexture) {
4281 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4282 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4284 IWineD3DBaseTexture_Release(oldTexture);
4285 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4290 if(bindCount && old->baseTexture.sampler == Stage) {
4292 /* Have to do a search for the other sampler(s) where the texture is bound to
4293 * Shouldn't happen as long as apps bind a texture only to one stage
4295 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4296 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4297 if(This->updateStateBlock->textures[i] == oldTexture) {
4298 old->baseTexture.sampler = i;
4305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4307 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4308 * pixel shader is used
4310 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4311 IWineD3DDeviceImpl_FindTexUnitMap(This);
4317 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4321 /* Reject invalid texture units */
4322 if (Stage >= GL_LIMITS(sampler_stages)) {
4323 TRACE("Attempt to access invalid texture rejected\n");
4324 return WINED3DERR_INVALIDCALL;
4326 *ppTexture=This->stateBlock->textures[Stage];
4328 IWineD3DBaseTexture_AddRef(*ppTexture);
4336 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4337 IWineD3DSurface **ppBackBuffer) {
4338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4339 IWineD3DSwapChain *swapChain;
4342 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4344 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4345 if (hr == WINED3D_OK) {
4346 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4347 IWineD3DSwapChain_Release(swapChain);
4349 *ppBackBuffer = NULL;
4354 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4356 WARN("(%p) : stub, calling idirect3d for now\n", This);
4357 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4360 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4362 IWineD3DSwapChain *swapChain;
4365 if(iSwapChain > 0) {
4366 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4367 if (hr == WINED3D_OK) {
4368 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4369 IWineD3DSwapChain_Release(swapChain);
4371 FIXME("(%p) Error getting display mode\n", This);
4374 /* Don't read the real display mode,
4375 but return the stored mode instead. X11 can't change the color
4376 depth, and some apps are pretty angry if they SetDisplayMode from
4377 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4379 Also don't relay to the swapchain because with ddraw it's possible
4380 that there isn't a swapchain at all */
4381 pMode->Width = This->ddraw_width;
4382 pMode->Height = This->ddraw_height;
4383 pMode->Format = This->ddraw_format;
4384 pMode->RefreshRate = 0;
4391 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4393 TRACE("(%p)->(%p)\n", This, hWnd);
4395 This->ddraw_window = hWnd;
4399 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4401 TRACE("(%p)->(%p)\n", This, hWnd);
4403 *hWnd = This->ddraw_window;
4408 * Stateblock related functions
4411 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4413 IWineD3DStateBlockImpl *object;
4414 HRESULT temp_result;
4416 TRACE("(%p)\n", This);
4418 if (This->isRecordingState) {
4419 return WINED3DERR_INVALIDCALL;
4422 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4423 if (NULL == object ) {
4424 FIXME("(%p)Error allocating memory for stateblock\n", This);
4425 return E_OUTOFMEMORY;
4427 TRACE("(%p) created object %p\n", This, object);
4428 object->wineD3DDevice= This;
4429 /** FIXME: object->parent = parent; **/
4430 object->parent = NULL;
4431 object->blockType = WINED3DSBT_ALL;
4433 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4435 temp_result = allocate_shader_constants(object);
4436 if (WINED3D_OK != temp_result)
4439 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4440 This->updateStateBlock = object;
4441 This->isRecordingState = TRUE;
4443 TRACE("(%p) recording stateblock %p\n",This , object);
4447 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4450 if (!This->isRecordingState) {
4451 FIXME("(%p) not recording! returning error\n", This);
4452 *ppStateBlock = NULL;
4453 return WINED3DERR_INVALIDCALL;
4456 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4457 This->isRecordingState = FALSE;
4458 This->updateStateBlock = This->stateBlock;
4459 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4460 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4461 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4466 * Scene related functions
4468 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4469 /* At the moment we have no need for any functionality at the beginning
4471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 TRACE("(%p) : stub\n", This);
4476 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 TRACE("(%p)\n", This);
4480 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4482 checkGLcall("glFlush");
4484 TRACE("End Scene\n");
4485 /* If we're using FBOs this isn't needed */
4486 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4488 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4489 IUnknown *targetContainer = NULL;
4490 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4491 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4492 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4493 /** always dirtify for now. we must find a better way to see that surface have been modified
4494 (Modifications should will only occur via draw-primitive, but we do need better locking
4495 switching to render-to-texture should remove the overhead though.
4497 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4498 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4499 IWineD3DSurface_PreLoad(This->render_targets[0]);
4500 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4501 IUnknown_Release(targetContainer);
4504 This->sceneEnded = TRUE;
4509 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4510 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4511 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4513 IWineD3DSwapChain *swapChain = NULL;
4515 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4517 TRACE("(%p) Presenting the frame\n", This);
4519 for(i = 0 ; i < swapchains ; i ++) {
4521 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4522 TRACE("presentinng chain %d, %p\n", i, swapChain);
4523 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4524 IWineD3DSwapChain_Release(swapChain);
4530 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4531 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4534 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4535 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4536 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4537 GLbitfield glMask = 0;
4538 GLboolean old_ztest;
4539 GLfloat old_z_clear_value;
4540 GLint old_stencil_clear_value;
4541 GLfloat old_color_clear_value[4];
4543 CONST WINED3DRECT* curRect;
4545 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4546 Count, pRects, Flags, Z, Stencil);
4550 glEnable(GL_SCISSOR_TEST);
4551 checkGLcall("glEnable GL_SCISSOR_TEST");
4553 if (Count > 0 && pRects) {
4559 /* Only set the values up once, as they are not changing */
4560 if (Flags & WINED3DCLEAR_STENCIL) {
4561 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4562 glClearStencil(Stencil);
4563 checkGLcall("glClearStencil");
4564 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4565 glStencilMask(0xFFFFFFFF);
4568 if (Flags & WINED3DCLEAR_ZBUFFER) {
4569 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4570 glDepthMask(GL_TRUE);
4571 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4573 checkGLcall("glClearDepth");
4574 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4577 if (Flags & WINED3DCLEAR_TARGET) {
4578 TRACE("Clearing screen with glClear to color %x\n", Color);
4579 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4580 glClearColor(D3DCOLOR_R(Color),
4584 checkGLcall("glClearColor");
4586 /* Clear ALL colors! */
4587 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4588 glMask = glMask | GL_COLOR_BUFFER_BIT;
4591 /* Now process each rect in turn */
4592 for (i = 0; i < Count || i == 0; i++) {
4595 /* Note gl uses lower left, width/height */
4596 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4597 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4598 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4599 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4600 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4601 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4602 checkGLcall("glScissor");
4604 glScissor(This->stateBlock->viewport.X,
4605 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4606 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4607 This->stateBlock->viewport.Width,
4608 This->stateBlock->viewport.Height);
4609 checkGLcall("glScissor");
4612 /* Clear the selected rectangle (or full screen) */
4614 checkGLcall("glClear");
4616 /* Step to the next rectangle */
4617 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4620 /* Restore the old values (why..?) */
4621 if (Flags & WINED3DCLEAR_STENCIL) {
4622 glClearStencil(old_stencil_clear_value);
4623 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4625 if (Flags & WINED3DCLEAR_ZBUFFER) {
4626 glDepthMask(old_ztest);
4627 glClearDepth(old_z_clear_value);
4629 if (Flags & WINED3DCLEAR_TARGET) {
4630 glClearColor(old_color_clear_value[0],
4631 old_color_clear_value[1],
4632 old_color_clear_value[2],
4633 old_color_clear_value[3]);
4634 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4635 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4636 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4637 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4640 glDisable(GL_SCISSOR_TEST);
4641 checkGLcall("glDisable");
4650 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4651 UINT PrimitiveCount) {
4653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4654 This->stateBlock->streamIsUP = FALSE;
4656 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4657 debug_d3dprimitivetype(PrimitiveType),
4658 StartVertex, PrimitiveCount);
4660 if(This->stateBlock->loadBaseVertexIndex != 0) {
4661 This->stateBlock->loadBaseVertexIndex = 0;
4662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4664 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4665 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4666 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4670 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4671 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4672 WINED3DPRIMITIVETYPE PrimitiveType,
4673 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4677 IWineD3DIndexBuffer *pIB;
4678 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4680 pIB = This->stateBlock->pIndexData;
4681 This->stateBlock->streamIsUP = FALSE;
4683 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4684 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4685 minIndex, NumVertices, startIndex, primCount);
4687 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4688 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4694 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4695 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4699 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4700 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4705 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4706 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4707 UINT VertexStreamZeroStride) {
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4710 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4711 debug_d3dprimitivetype(PrimitiveType),
4712 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4714 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4715 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4716 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4717 This->stateBlock->streamIsUP = TRUE;
4718 This->stateBlock->loadBaseVertexIndex = 0;
4720 /* TODO: Only mark dirty if drawing from a different UP address */
4721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4723 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4724 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4726 /* MSDN specifies stream zero settings must be set to NULL */
4727 This->stateBlock->streamStride[0] = 0;
4728 This->stateBlock->streamSource[0] = NULL;
4730 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4731 * the new stream sources or use UP drawing again
4736 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4737 UINT MinVertexIndex, UINT NumVertices,
4738 UINT PrimitiveCount, CONST void* pIndexData,
4739 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4740 UINT VertexStreamZeroStride) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4744 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4745 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4746 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4747 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4749 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4755 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4756 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4757 This->stateBlock->streamIsUP = TRUE;
4758 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4760 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4761 This->stateBlock->baseVertexIndex = 0;
4762 This->stateBlock->loadBaseVertexIndex = 0;
4763 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4766 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4768 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4769 This->stateBlock->streamSource[0] = NULL;
4770 This->stateBlock->streamStride[0] = 0;
4771 This->stateBlock->pIndexData = NULL;
4772 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4773 * SetStreamSource to specify a vertex buffer
4779 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4782 /* Mark the state dirty until we have nicer tracking
4783 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4787 This->stateBlock->baseVertexIndex = 0;
4788 This->up_strided = DrawPrimStrideData;
4789 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4790 This->up_strided = NULL;
4793 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4794 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4796 HRESULT hr = WINED3D_OK;
4797 WINED3DRESOURCETYPE sourceType;
4798 WINED3DRESOURCETYPE destinationType;
4801 /* TODO: think about moving the code into IWineD3DBaseTexture */
4803 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4805 /* verify that the source and destination textures aren't NULL */
4806 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4807 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4808 This, pSourceTexture, pDestinationTexture);
4809 hr = WINED3DERR_INVALIDCALL;
4812 if (pSourceTexture == pDestinationTexture) {
4813 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4814 This, pSourceTexture, pDestinationTexture);
4815 hr = WINED3DERR_INVALIDCALL;
4817 /* Verify that the source and destination textures are the same type */
4818 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4819 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4821 if (sourceType != destinationType) {
4822 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4824 hr = WINED3DERR_INVALIDCALL;
4827 /* check that both textures have the identical numbers of levels */
4828 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4829 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4830 hr = WINED3DERR_INVALIDCALL;
4833 if (WINED3D_OK == hr) {
4835 /* Make sure that the destination texture is loaded */
4836 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4838 /* Update every surface level of the texture */
4839 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4841 switch (sourceType) {
4842 case WINED3DRTYPE_TEXTURE:
4844 IWineD3DSurface *srcSurface;
4845 IWineD3DSurface *destSurface;
4847 for (i = 0 ; i < levels ; ++i) {
4848 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4849 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4850 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4851 IWineD3DSurface_Release(srcSurface);
4852 IWineD3DSurface_Release(destSurface);
4853 if (WINED3D_OK != hr) {
4854 WARN("(%p) : Call to update surface failed\n", This);
4860 case WINED3DRTYPE_CUBETEXTURE:
4862 IWineD3DSurface *srcSurface;
4863 IWineD3DSurface *destSurface;
4864 WINED3DCUBEMAP_FACES faceType;
4866 for (i = 0 ; i < levels ; ++i) {
4867 /* Update each cube face */
4868 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4869 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4870 if (WINED3D_OK != hr) {
4871 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4873 TRACE("Got srcSurface %p\n", srcSurface);
4875 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4876 if (WINED3D_OK != hr) {
4877 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4879 TRACE("Got desrSurface %p\n", destSurface);
4881 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4882 IWineD3DSurface_Release(srcSurface);
4883 IWineD3DSurface_Release(destSurface);
4884 if (WINED3D_OK != hr) {
4885 WARN("(%p) : Call to update surface failed\n", This);
4892 #if 0 /* TODO: Add support for volume textures */
4893 case WINED3DRTYPE_VOLUMETEXTURE:
4895 IWineD3DVolume srcVolume = NULL;
4896 IWineD3DSurface destVolume = NULL;
4898 for (i = 0 ; i < levels ; ++i) {
4899 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4900 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4901 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4902 IWineD3DVolume_Release(srcSurface);
4903 IWineD3DVolume_Release(destSurface);
4904 if (WINED3D_OK != hr) {
4905 WARN("(%p) : Call to update volume failed\n", This);
4913 FIXME("(%p) : Unsupported source and destination type\n", This);
4914 hr = WINED3DERR_INVALIDCALL;
4921 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
4922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4923 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
4924 * NOTE It may be best to move the code into surface to occomplish this
4925 ****************************************/
4927 WINED3DSURFACE_DESC surfaceDesc;
4928 unsigned int surfaceWidth, surfaceHeight;
4929 glDescriptor *targetGlDescription = NULL;
4930 glDescriptor *surfaceGlDescription = NULL;
4931 IWineD3DSwapChainImpl *container = NULL;
4933 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
4934 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
4935 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
4937 surfaceDesc.Width = &surfaceWidth;
4938 surfaceDesc.Height = &surfaceHeight;
4939 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
4940 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
4942 /* Ok, I may need to setup some kind of active swapchain reference on the device */
4943 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
4945 /* TODO: opengl Context switching for swapchains etc... */
4946 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
4947 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
4948 glReadBuffer(GL_BACK);
4949 vcheckGLcall("glReadBuffer(GL_BACK)");
4950 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
4951 glReadBuffer(GL_FRONT);
4952 vcheckGLcall("glReadBuffer(GL_FRONT)");
4953 } else if (pRenderTarget == This->depthStencilBuffer) {
4954 FIXME("Reading of depthstencil not yet supported\n");
4961 surfaceGlDescription->glFormat,
4962 surfaceGlDescription->glType,
4963 (void *)IWineD3DSurface_GetData(pSurface));
4964 vcheckGLcall("glReadPixels(...)");
4965 if(NULL != container ){
4966 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
4969 IWineD3DBaseTexture *container;
4970 GLenum textureDimensions = GL_TEXTURE_2D;
4972 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
4973 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
4974 IWineD3DBaseTexture_Release(container);
4976 /* TODO: 2D -> Cube surface coppies etc.. */
4977 if (surfaceGlDescription->target != textureDimensions) {
4978 FIXME("(%p) : Texture dimension mismatch\n", This);
4980 glEnable(textureDimensions);
4981 vcheckGLcall("glEnable(GL_TEXTURE_...)");
4982 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
4983 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
4984 vcheckGLcall("glBindTexture");
4985 glGetTexImage(surfaceGlDescription->target,
4986 surfaceGlDescription->level,
4987 surfaceGlDescription->glFormat,
4988 surfaceGlDescription->glType,
4989 (void *)IWineD3DSurface_GetData(pSurface));
4990 glDisable(textureDimensions);
4991 vcheckGLcall("glDisable(GL_TEXTURE_...)");
4998 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4999 IWineD3DSwapChain *swapChain;
5001 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5002 if(hr == WINED3D_OK) {
5003 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5004 IWineD3DSwapChain_Release(swapChain);
5009 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 /* return a sensible default */
5013 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5014 FIXME("(%p) : stub\n", This);
5018 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5021 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5022 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5023 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5024 return WINED3DERR_INVALIDCALL;
5026 for (j = 0; j < 256; ++j) {
5027 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5028 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5029 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5030 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5032 TRACE("(%p) : returning\n", This);
5036 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5039 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5040 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5041 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5042 return WINED3DERR_INVALIDCALL;
5044 for (j = 0; j < 256; ++j) {
5045 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5046 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5047 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5048 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5050 TRACE("(%p) : returning\n", This);
5054 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5056 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5057 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5058 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5059 return WINED3DERR_INVALIDCALL;
5061 /*TODO: stateblocks */
5062 This->currentPalette = PaletteNumber;
5063 TRACE("(%p) : returning\n", This);
5067 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5069 if (PaletteNumber == NULL) {
5070 WARN("(%p) : returning Invalid Call\n", This);
5071 return WINED3DERR_INVALIDCALL;
5073 /*TODO: stateblocks */
5074 *PaletteNumber = This->currentPalette;
5075 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5079 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5081 static BOOL showFixmes = TRUE;
5083 FIXME("(%p) : stub\n", This);
5087 This->softwareVertexProcessing = bSoftware;
5092 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5094 static BOOL showFixmes = TRUE;
5096 FIXME("(%p) : stub\n", This);
5099 return This->softwareVertexProcessing;
5103 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5105 IWineD3DSwapChain *swapChain;
5108 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5110 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5111 if(hr == WINED3D_OK){
5112 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5113 IWineD3DSwapChain_Release(swapChain);
5115 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5121 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5123 static BOOL showfixmes = TRUE;
5124 if(nSegments != 0.0f) {
5126 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5133 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 static BOOL showfixmes = TRUE;
5137 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5143 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5145 /** TODO: remove casts to IWineD3DSurfaceImpl
5146 * NOTE: move code to surface to accomplish this
5147 ****************************************/
5148 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5149 int srcWidth, srcHeight;
5150 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5151 WINED3DFORMAT destFormat, srcFormat;
5153 int srcLeft, destLeft, destTop;
5154 WINED3DPOOL srcPool, destPool;
5156 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5157 glDescriptor *glDescription = NULL;
5158 GLenum textureDimensions = GL_TEXTURE_2D;
5159 IWineD3DBaseTexture *baseTexture;
5161 WINED3DSURFACE_DESC winedesc;
5163 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5164 memset(&winedesc, 0, sizeof(winedesc));
5165 winedesc.Width = &srcSurfaceWidth;
5166 winedesc.Height = &srcSurfaceHeight;
5167 winedesc.Pool = &srcPool;
5168 winedesc.Format = &srcFormat;
5170 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5172 winedesc.Width = &destSurfaceWidth;
5173 winedesc.Height = &destSurfaceHeight;
5174 winedesc.Pool = &destPool;
5175 winedesc.Format = &destFormat;
5176 winedesc.Size = &destSize;
5178 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5180 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5181 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5182 return WINED3DERR_INVALIDCALL;
5185 if (destFormat == WINED3DFMT_UNKNOWN) {
5186 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5187 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5189 /* Get the update surface description */
5190 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5193 /* Make sure the surface is loaded and up to date */
5194 IWineD3DSurface_PreLoad(pDestinationSurface);
5196 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5200 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5201 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5202 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5203 srcLeft = pSourceRect ? pSourceRect->left : 0;
5204 destLeft = pDestPoint ? pDestPoint->x : 0;
5205 destTop = pDestPoint ? pDestPoint->y : 0;
5208 /* This function doesn't support compressed textures
5209 the pitch is just bytesPerPixel * width */
5210 if(srcWidth != srcSurfaceWidth || srcLeft ){
5211 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5212 offset += srcLeft * pSrcSurface->bytesPerPixel;
5213 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5215 /* TODO DXT formats */
5217 if(pSourceRect != NULL && pSourceRect->top != 0){
5218 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5220 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5222 ,glDescription->level
5227 ,glDescription->glFormat
5228 ,glDescription->glType
5229 ,IWineD3DSurface_GetData(pSourceSurface)
5233 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5235 /* need to lock the surface to get the data */
5236 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5239 /* TODO: Cube and volume support */
5241 /* not a whole row so we have to do it a line at a time */
5244 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5245 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5247 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5249 glTexSubImage2D(glDescription->target
5250 ,glDescription->level
5255 ,glDescription->glFormat
5256 ,glDescription->glType
5257 ,data /* could be quicker using */
5262 } else { /* Full width, so just write out the whole texture */
5264 if (WINED3DFMT_DXT1 == destFormat ||
5265 WINED3DFMT_DXT2 == destFormat ||
5266 WINED3DFMT_DXT3 == destFormat ||
5267 WINED3DFMT_DXT4 == destFormat ||
5268 WINED3DFMT_DXT5 == destFormat) {
5269 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5270 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5271 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5272 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5273 } if (destFormat != srcFormat) {
5274 FIXME("Updating mixed format compressed texture is not curretly support\n");
5276 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5277 glDescription->level,
5278 glDescription->glFormatInternal,
5283 IWineD3DSurface_GetData(pSourceSurface));
5286 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5291 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5293 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5294 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5295 data returned by GetData non-power2 width/height with hardware non-power2
5296 pow2Width/height are set to surface width height, repacking isn't needed so it
5297 doesn't matter which function gets called. */
5298 glTexSubImage2D(glDescription->target
5299 ,glDescription->level
5304 ,glDescription->glFormat
5305 ,glDescription->glType
5306 ,IWineD3DSurface_GetData(pSourceSurface)
5310 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5311 glTexSubImage2D(glDescription->target
5312 ,glDescription->level
5315 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5316 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5317 ,glDescription->glFormat
5318 ,glDescription->glType
5319 ,IWineD3DSurface_GetData(pSourceSurface)
5325 checkGLcall("glTexSubImage2D");
5326 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5328 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5329 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5330 * surface bigger than it needs to be hmm.. */
5331 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5332 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5333 IWineD3DBaseTexture_Release(baseTexture);
5336 glDisable(textureDimensions); /* This needs to be managed better.... */
5342 /* Implementation details at http://developer.nvidia.com/attach/6494
5344 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5345 hmm.. no longer supported use
5346 OpenGL evaluators or tessellate surfaces within your application.
5349 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5350 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5352 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5353 FIXME("(%p) : Stub\n", This);
5358 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5359 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5361 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5362 FIXME("(%p) : Stub\n", This);
5366 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5368 TRACE("(%p) Handle(%d)\n", This, Handle);
5369 FIXME("(%p) : Stub\n", This);
5373 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5375 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5377 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5379 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5380 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5381 return WINED3DERR_INVALIDCALL;
5384 /* Just forward this to the DirectDraw blitting engine */
5385 memset(&BltFx, 0, sizeof(BltFx));
5386 BltFx.dwSize = sizeof(BltFx);
5387 BltFx.u5.dwFillColor = color;
5388 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5391 /* rendertarget and deptth stencil functions */
5392 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5395 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5396 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5397 return WINED3DERR_INVALIDCALL;
5400 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5401 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5402 /* Note inc ref on returned surface */
5403 if(*ppRenderTarget != NULL)
5404 IWineD3DSurface_AddRef(*ppRenderTarget);
5408 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5410 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5411 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5412 IWineD3DSwapChainImpl *Swapchain;
5415 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5417 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5418 if(hr != WINED3D_OK) {
5419 ERR("Can't get the swapchain\n");
5423 /* Make sure to release the swapchain */
5424 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5426 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5427 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5428 return WINED3DERR_INVALIDCALL;
5430 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5431 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5432 return WINED3DERR_INVALIDCALL;
5435 if(Swapchain->frontBuffer != Front) {
5436 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5438 if(Swapchain->frontBuffer)
5439 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5440 Swapchain->frontBuffer = Front;
5442 if(Swapchain->frontBuffer) {
5443 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5447 if(Back && !Swapchain->backBuffer) {
5448 /* We need memory for the back buffer array - only one back buffer this way */
5449 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5450 if(!Swapchain->backBuffer) {
5451 ERR("Out of memory\n");
5452 return E_OUTOFMEMORY;
5456 if(Swapchain->backBuffer[0] != Back) {
5457 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5459 if(!Swapchain->backBuffer[0]) {
5460 /* GL was told to draw to the front buffer at creation,
5463 glDrawBuffer(GL_BACK);
5464 checkGLcall("glDrawBuffer(GL_BACK)");
5465 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5466 Swapchain->presentParms.BackBufferCount = 1;
5468 /* That makes problems - disable for now */
5469 /* glDrawBuffer(GL_FRONT); */
5470 checkGLcall("glDrawBuffer(GL_FRONT)");
5471 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5472 Swapchain->presentParms.BackBufferCount = 0;
5476 if(Swapchain->backBuffer[0])
5477 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5478 Swapchain->backBuffer[0] = Back;
5480 if(Swapchain->backBuffer[0]) {
5481 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5483 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5491 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5493 *ppZStencilSurface = This->depthStencilBuffer;
5494 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5496 if(*ppZStencilSurface != NULL) {
5497 /* Note inc ref on returned surface */
5498 IWineD3DSurface_AddRef(*ppZStencilSurface);
5503 static void bind_fbo(IWineD3DDevice *iface) {
5504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5507 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5508 checkGLcall("glGenFramebuffersEXT()");
5510 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5511 checkGLcall("glBindFramebuffer()");
5514 /* TODO: Handle stencil attachments */
5515 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5517 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5519 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5523 if (depth_stencil_impl) {
5524 GLenum texttarget, target;
5525 GLint old_binding = 0;
5527 IWineD3DSurface_PreLoad(depth_stencil);
5528 texttarget = depth_stencil_impl->glDescription.target;
5529 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5531 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5532 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5533 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5534 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5535 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5536 glBindTexture(target, old_binding);
5538 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5539 checkGLcall("glFramebufferTexture2DEXT()");
5541 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5542 checkGLcall("glFramebufferTexture2DEXT()");
5545 if (!This->render_offscreen) {
5546 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5547 checkGLcall("glBindFramebuffer()");
5551 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5553 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5555 if (idx >= GL_LIMITS(buffers)) {
5556 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5562 GLenum texttarget, target;
5563 GLint old_binding = 0;
5565 IWineD3DSurface_PreLoad(render_target);
5566 texttarget = rtimpl->glDescription.target;
5567 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5569 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5570 glBindTexture(target, rtimpl->glDescription.textureName);
5571 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5572 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5573 glBindTexture(target, old_binding);
5575 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5576 checkGLcall("glFramebufferTexture2DEXT()");
5578 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5580 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5581 checkGLcall("glFramebufferTexture2DEXT()");
5583 This->draw_buffers[idx] = GL_NONE;
5586 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5587 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5588 checkGLcall("glDrawBuffers()");
5591 if (!This->render_offscreen) {
5592 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5593 checkGLcall("glBindFramebuffer()");
5597 /* internal static helper functions */
5598 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5599 IWineD3DSurface *RenderSurface);
5601 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 HRESULT hr = WINED3D_OK;
5604 WINED3DVIEWPORT viewport;
5606 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5608 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5609 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5610 return WINED3DERR_INVALIDCALL;
5613 /* MSDN says that null disables the render target
5614 but a device must always be associated with a render target
5615 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5617 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5620 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5621 FIXME("Trying to set render target 0 to NULL\n");
5622 return WINED3DERR_INVALIDCALL;
5624 /* TODO: replace Impl* usage with interface usage */
5625 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5626 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);
5627 return WINED3DERR_INVALIDCALL;
5629 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5630 * builds, but I think wine counts as a 'debug' build for now.
5631 ******************************/
5632 /* If we are trying to set what we already have, don't bother */
5633 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5634 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5636 /* Otherwise, set the render target up */
5638 if (!This->sceneEnded) {
5639 IWineD3DDevice_EndScene(iface);
5641 TRACE("clearing renderer\n");
5642 /* IWineD3DDeviceImpl_CleanRender(iface); */
5643 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5644 depending on the renter target implementation being used.
5645 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5646 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5647 stencil buffer and incure an extra memory overhead */
5648 if (RenderTargetIndex == 0) {
5649 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5654 /* Replace the render target */
5655 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5656 This->render_targets[RenderTargetIndex] = pRenderTarget;
5657 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5659 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5660 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5664 if (SUCCEEDED(hr)) {
5665 /* Finally, reset the viewport as the MSDN states. */
5666 /* TODO: Replace impl usage */
5667 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5668 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5671 viewport.MaxZ = 1.0f;
5672 viewport.MinZ = 0.0f;
5673 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5675 FIXME("Unknown error setting the render target\n");
5677 This->sceneEnded = FALSE;
5681 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5683 HRESULT hr = WINED3D_OK;
5684 IWineD3DSurface *tmp;
5686 TRACE("(%p) Swapping z-buffer\n",This);
5688 if (pNewZStencil == This->stencilBufferTarget) {
5689 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5691 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5692 * depending on the renter target implementation being used.
5693 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5694 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5695 * stencil buffer and incure an extra memory overhead
5696 ******************************************************/
5699 tmp = This->stencilBufferTarget;
5700 This->stencilBufferTarget = pNewZStencil;
5701 /* should we be calling the parent or the wined3d surface? */
5702 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5703 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5705 /** TODO: glEnable/glDisable on depth/stencil depending on
5706 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5707 **********************************************************/
5708 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5709 set_depth_stencil_fbo(iface, pNewZStencil);
5717 #ifdef GL_VERSION_1_3
5718 /* Internal functions not in DirectX */
5719 /** TODO: move this off to the opengl context manager
5720 *(the swapchain doesn't need to know anything about offscreen rendering!)
5721 ****************************************************/
5723 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5727 TRACE("(%p), %p\n", This, swapchain);
5729 if (swapchain->win != swapchain->drawable) {
5730 /* Set everything back the way it ws */
5731 swapchain->render_ctx = swapchain->glCtx;
5732 swapchain->drawable = swapchain->win;
5737 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5738 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5742 unsigned int height;
5743 WINED3DFORMAT format;
5744 WINED3DSURFACE_DESC surfaceDesc;
5745 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5746 surfaceDesc.Width = &width;
5747 surfaceDesc.Height = &height;
5748 surfaceDesc.Format = &format;
5749 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5751 /* I need a get width/height function (and should do something with the format) */
5752 for (i = 0; i < CONTEXT_CACHE; ++i) {
5753 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5754 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5755 the pSurface can be set to 0 allowing it to be reused from cache **/
5756 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5757 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5758 *context = &This->contextCache[i];
5761 if (This->contextCache[i].Width == 0) {
5762 This->contextCache[i].pSurface = pSurface;
5763 This->contextCache[i].Width = width;
5764 This->contextCache[i].Height = height;
5765 *context = &This->contextCache[i];
5769 if (i == CONTEXT_CACHE) {
5770 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5771 glContext *dropContext = 0;
5772 for (i = 0; i < CONTEXT_CACHE; i++) {
5773 if (This->contextCache[i].usedcount < minUsage) {
5774 dropContext = &This->contextCache[i];
5775 minUsage = This->contextCache[i].usedcount;
5778 /* clean up the context (this doesn't work for ATI at the moment */
5780 glXDestroyContext(swapchain->display, dropContext->context);
5781 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5784 dropContext->Width = 0;
5785 dropContext->pSurface = pSurface;
5786 *context = dropContext;
5788 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5789 for (i = 0; i < CONTEXT_CACHE; i++) {
5790 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
5794 if (*context != NULL)
5797 return E_OUTOFMEMORY;
5801 /* Reapply the device stateblock */
5802 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
5805 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5808 /* Disable recording */
5809 oldUpdateStateBlock = This->updateStateBlock;
5810 oldRecording= This->isRecordingState;
5811 This->isRecordingState = FALSE;
5812 This->updateStateBlock = This->stateBlock;
5814 /* Reapply the state block */
5815 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
5817 /* Temporaryily mark all render states dirty to force reapplication
5818 * until the context management for is integrated with the state management
5819 * The same for the pixel shader, vertex declaration and vertex shader
5820 * Sampler states and texture stage states are marked
5821 * dirty my StateBlock::Apply already.
5823 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
5824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
5826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
5830 /* Restore recording */
5831 This->isRecordingState = oldRecording;
5832 This->updateStateBlock = oldUpdateStateBlock;
5835 /* Set offscreen rendering. When rendering offscreen the surface will be
5836 * rendered upside down to compensate for the fact that D3D texture coordinates
5837 * are flipped compared to GL texture coordinates. The cullmode is affected by
5838 * this, so it must be updated. To update the cullmode stateblock recording has
5839 * to be temporarily disabled. The new state management code will hopefully
5840 * make this unnecessary */
5841 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
5844 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5846 /* Nothing to update, return. */
5847 if (This->render_offscreen == isTexture) return;
5849 /* Disable recording */
5850 oldUpdateStateBlock = This->updateStateBlock;
5851 oldRecording= This->isRecordingState;
5852 This->isRecordingState = FALSE;
5853 This->updateStateBlock = This->stateBlock;
5855 This->render_offscreen = isTexture;
5856 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
5857 This->depth_copy_state = WINED3D_DCS_COPY;
5859 This->last_was_rhw = FALSE;
5860 /* Viewport state will reapply the projection matrix for now */
5861 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
5863 /* Restore recording */
5864 This->isRecordingState = oldRecording;
5865 This->updateStateBlock = oldUpdateStateBlock;
5868 /* Returns an array of compatible FBconfig(s).
5869 * The array must be freed with XFree. Requires ENTER_GL() */
5871 static GLXFBConfig* device_find_fbconfigs(
5872 IWineD3DDeviceImpl* This,
5873 IWineD3DSwapChainImpl* implicitSwapchainImpl,
5874 IWineD3DSurface* RenderSurface) {
5876 GLXFBConfig* cfgs = NULL;
5881 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
5882 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
5883 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
5886 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5887 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5890 #define PUSH1(att) attribs[nAttribs++] = (att);
5891 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5893 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
5895 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
5896 PUSH2(GLX_X_RENDERABLE, TRUE);
5897 PUSH2(GLX_DOUBLEBUFFER, TRUE);
5898 TRACE("calling makeglcfg\n");
5899 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
5901 TRACE("calling chooseFGConfig\n");
5902 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5903 DefaultScreen(implicitSwapchainImpl->display),
5906 /* OK we didn't find the exact config, so use any reasonable match */
5907 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
5909 static BOOL show_message = TRUE;
5911 ERR("Failed to find exact match, finding alternative but you may "
5912 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
5913 show_message = FALSE;
5916 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
5917 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
5918 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
5919 PUSH2(GLX_DOUBLEBUFFER, FALSE);
5920 TRACE("calling makeglcfg\n");
5921 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
5923 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
5924 DefaultScreen(implicitSwapchainImpl->display),
5929 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
5930 BackBufferFormat, debug_d3dformat(BackBufferFormat),
5931 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
5935 for (i = 0; i < nCfgs; ++i) {
5936 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
5937 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
5938 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
5940 if (NULL != This->renderTarget) {
5942 vcheckGLcall("glFlush");
5943 /** This is only useful if the old render target was a swapchain,
5944 * we need to supercede this with a function that displays
5945 * the current buffer on the screen. This is easy to do in glx1.3 but
5946 * we need to do copy-write pixels in glx 1.2.
5947 ************************************************/
5948 glXSwapBuffers(implicitSwapChainImpl->display,
5949 implicitSwapChainImpl->drawable);
5950 printf("Hit Enter to get next frame ...\n");
5961 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
5962 * the functionality needs splitting up so that we don't do more than we should do.
5963 * this only seems to impact performance a little.
5964 ******************************/
5965 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5966 IWineD3DSurface *RenderSurface) {
5969 * Currently only active for GLX >= 1.3
5970 * for others versions we'll have to use GLXPixmaps
5972 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
5973 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
5974 * so only check OpenGL version
5975 * ..........................
5976 * I don't believe that it is a problem with NVidia headers,
5977 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
5978 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
5980 * Your application will report GLX version 1.2 on glXQueryVersion.
5981 * However, it is safe to call the GLX 1.3 functions as described below.
5983 #if defined(GL_VERSION_1_3)
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 GLXFBConfig* cfgs = NULL;
5987 IWineD3DSwapChain *currentSwapchain;
5988 IWineD3DSwapChainImpl *currentSwapchainImpl;
5989 IWineD3DSwapChain *implicitSwapchain;
5990 IWineD3DSwapChainImpl *implicitSwapchainImpl;
5991 IWineD3DSwapChain *renderSurfaceSwapchain;
5992 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
5994 /* Obtain a reference to the device implicit swapchain,
5995 * the swapchain of the current render target,
5996 * and the swapchain of the new render target.
5997 * Fallback to device implicit swapchain if the current render target doesn't have one */
5998 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
5999 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6000 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)¤tSwapchain);
6001 if (currentSwapchain == NULL)
6002 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
6004 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6005 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6006 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6011 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6012 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6013 **********************************************************************/
6014 if (renderSurfaceSwapchain != NULL) {
6016 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6017 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6018 TRACE("making swapchain active\n");
6019 if (RenderSurface != This->render_targets[0]) {
6020 BOOL backbuf = FALSE;
6023 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6024 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6032 /* This could be flagged so that some operations work directly with the front buffer */
6033 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6035 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6036 renderSurfaceSwapchainImpl->win,
6037 renderSurfaceSwapchainImpl->glCtx) == False) {
6039 TRACE("Error in setting current context: context %p drawable %ld !\n",
6040 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6042 checkGLcall("glXMakeContextCurrent");
6044 /* Clean up the old context */
6045 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6047 /* Reapply the stateblock, and set the device not to render to texture */
6048 device_reapply_stateblock(This);
6049 device_render_to_texture(This, FALSE);
6052 /* Offscreen rendering: PBuffers (currently disabled).
6053 * Also note that this path is never reached if FBOs are supported */
6054 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6055 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6057 /** ********************************************************************
6058 * This is a quickly hacked out implementation of offscreen textures.
6059 * It will work in most cases but there may be problems if the client
6060 * modifies the texture directly, or expects the contents of the rendertarget
6063 * There are some real speed vs compatibility issues here:
6064 * we should really use a new context for every texture, but that eats ram.
6065 * we should also be restoring the texture to the pbuffer but that eats CPU
6066 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6067 * but if this means reusing the display backbuffer then we need to make sure that
6068 * states are correctly preserved.
6069 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6070 * and gain a good performance increase at the cost of compatibility.
6071 * I would suggest that, when this is the case, a user configurable flag be made
6072 * available, allowing the user to choose the best emulated experience for them.
6073 *********************************************************************/
6075 XVisualInfo *visinfo;
6076 glContext *newContext;
6078 /* Here were using a shared context model */
6079 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6080 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6083 /* If the context doesn't exist then create a new one */
6084 /* TODO: This should really be part of findGlContext */
6085 if (NULL == newContext->context) {
6090 TRACE("making new buffer\n");
6091 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6092 attribs[nAttribs++] = newContext->Width;
6093 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6094 attribs[nAttribs++] = newContext->Height;
6095 attribs[nAttribs++] = None;
6097 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6099 /** ****************************************
6100 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6102 * In future releases, we may provide the calls glXCreateNewContext,
6103 * glXQueryDrawable and glXMakeContextCurrent.
6104 * so until then we have to use glXGetVisualFromFBConfig &co..
6105 ********************************************/
6107 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6109 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6111 newContext->context = glXCreateContext(
6112 implicitSwapchainImpl->display, visinfo,
6113 implicitSwapchainImpl->glCtx, GL_TRUE);
6118 if (NULL == newContext || NULL == newContext->context) {
6119 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6121 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6122 if (glXMakeCurrent(implicitSwapchainImpl->display,
6123 newContext->drawable, newContext->context) == False) {
6125 TRACE("Error in setting current context: context %p drawable %ld\n",
6126 newContext->context, newContext->drawable);
6128 checkGLcall("glXMakeContextCurrent");
6130 /* Clean up the old context */
6131 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6133 /* Reapply stateblock, and set device to render to a texture */
6134 device_reapply_stateblock(This);
6135 device_render_to_texture(This, TRUE);
6137 /* Set the current context of the swapchain to the new context */
6138 implicitSwapchainImpl->drawable = newContext->drawable;
6139 implicitSwapchainImpl->render_ctx = newContext->context;
6142 /* Same context, but update render_offscreen and cull mode */
6143 device_render_to_texture(This, TRUE);
6146 if (cfgs != NULL) XFree(cfgs);
6147 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6148 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6149 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6155 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6156 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6158 /* TODO: the use of Impl is deprecated. */
6159 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6161 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6163 /* some basic validation checks */
6164 if(This->cursorTexture) {
6166 glDeleteTextures(1, &This->cursorTexture);
6168 This->cursorTexture = 0;
6172 /* MSDN: Cursor must be A8R8G8B8 */
6173 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6174 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6175 return WINED3DERR_INVALIDCALL;
6178 /* MSDN: Cursor must be smaller than the display mode */
6179 if(pSur->currentDesc.Width > This->ddraw_width ||
6180 pSur->currentDesc.Height > This->ddraw_height) {
6181 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);
6182 return WINED3DERR_INVALIDCALL;
6185 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6186 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6187 * Texture and Blitting code to draw the cursor
6189 pSur->Flags |= SFLAG_FORCELOAD;
6190 IWineD3DSurface_PreLoad(pCursorBitmap);
6191 pSur->Flags &= ~SFLAG_FORCELOAD;
6192 /* Do not store the surface's pointer because the application may release
6193 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6194 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6196 This->cursorTexture = pSur->glDescription.textureName;
6197 This->cursorWidth = pSur->currentDesc.Width;
6198 This->cursorHeight = pSur->currentDesc.Height;
6199 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6202 This->xHotSpot = XHotSpot;
6203 This->yHotSpot = YHotSpot;
6207 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6209 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6211 This->xScreenSpace = XScreenSpace;
6212 This->yScreenSpace = YScreenSpace;
6218 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6220 BOOL oldVisible = This->bCursorVisible;
6221 TRACE("(%p) : visible(%d)\n", This, bShow);
6223 if(This->cursorTexture)
6224 This->bCursorVisible = bShow;
6229 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6231 TRACE("(%p) : state (%u)\n", This, This->state);
6232 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6233 switch (This->state) {
6236 case WINED3DERR_DEVICELOST:
6238 ResourceList *resourceList = This->resources;
6239 while (NULL != resourceList) {
6240 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6241 return WINED3DERR_DEVICENOTRESET;
6242 resourceList = resourceList->next;
6244 return WINED3DERR_DEVICELOST;
6246 case WINED3DERR_DRIVERINTERNALERROR:
6247 return WINED3DERR_DRIVERINTERNALERROR;
6251 return WINED3DERR_DRIVERINTERNALERROR;
6255 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6257 /** FIXME: Resource tracking needs to be done,
6258 * The closes we can do to this is set the priorities of all managed textures low
6259 * and then reset them.
6260 ***********************************************************/
6261 FIXME("(%p) : stub\n", This);
6265 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6266 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6267 if(surface->Flags & SFLAG_DIBSECTION) {
6268 /* Release the DC */
6269 SelectObject(surface->hDC, surface->dib.holdbitmap);
6270 DeleteDC(surface->hDC);
6271 /* Release the DIB section */
6272 DeleteObject(surface->dib.DIBsection);
6273 surface->dib.bitmap_data = NULL;
6274 surface->resource.allocatedMemory = NULL;
6275 surface->Flags &= ~SFLAG_DIBSECTION;
6277 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6278 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6279 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6280 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6281 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6283 surface->pow2Width = surface->pow2Height = 1;
6284 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6285 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6287 if(surface->glDescription.textureName) {
6289 glDeleteTextures(1, &surface->glDescription.textureName);
6291 surface->glDescription.textureName = 0;
6293 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6294 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6295 surface->Flags |= SFLAG_NONPOW2;
6297 surface->Flags &= ~SFLAG_NONPOW2;
6299 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6300 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6303 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6305 IWineD3DSwapChainImpl *swapchain;
6307 BOOL DisplayModeChanged = FALSE;
6308 WINED3DDISPLAYMODE mode;
6309 TRACE("(%p)\n", This);
6311 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6313 ERR("Failed to get the first implicit swapchain\n");
6317 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6318 * on an existing gl context, so there's no real need for recreation.
6320 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6322 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6324 TRACE("New params:\n");
6325 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6326 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6327 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6328 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6329 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6330 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6331 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6332 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6333 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6334 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6335 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6336 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6337 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6339 /* No special treatment of these parameters. Just store them */
6340 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6341 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6342 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6343 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6345 /* What to do about these? */
6346 if(*pPresentationParameters->BackBufferCount != 0 &&
6347 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6348 ERR("Cannot change the back buffer count yet\n");
6350 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6351 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6352 ERR("Cannot change the back buffer format yet\n");
6354 if(*pPresentationParameters->hDeviceWindow != NULL &&
6355 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6356 ERR("Cannot change the device window yet\n");
6358 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6359 ERR("What do do about a changed auto depth stencil parameter?\n");
6362 if(*pPresentationParameters->Windowed) {
6363 mode.Width = swapchain->orig_width;
6364 mode.Height = swapchain->orig_height;
6365 mode.RefreshRate = 0;
6366 mode.Format = swapchain->presentParms.BackBufferFormat;
6368 mode.Width = *pPresentationParameters->BackBufferWidth;
6369 mode.Height = *pPresentationParameters->BackBufferHeight;
6370 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6371 mode.Format = swapchain->presentParms.BackBufferFormat;
6374 /* Should Width == 800 && Height == 0 set 800x600? */
6375 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6376 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6377 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6384 vp.Width = *pPresentationParameters->BackBufferWidth;
6385 vp.Height = *pPresentationParameters->BackBufferHeight;
6389 if(!*pPresentationParameters->Windowed) {
6390 DisplayModeChanged = TRUE;
6392 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6393 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6395 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6396 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6397 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6400 /* Now set the new viewport */
6401 IWineD3DDevice_SetViewport(iface, &vp);
6404 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6405 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6406 DisplayModeChanged) {
6407 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6410 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6414 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6416 /** FIXME: always true at the moment **/
6417 if(!bEnableDialogs) {
6418 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6424 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6426 TRACE("(%p) : pParameters %p\n", This, pParameters);
6428 *pParameters = This->createParms;
6432 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6433 IWineD3DSwapChain *swapchain;
6434 HRESULT hrc = WINED3D_OK;
6436 TRACE("Relaying to swapchain\n");
6438 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6439 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6440 IWineD3DSwapChain_Release(swapchain);
6445 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6446 IWineD3DSwapChain *swapchain;
6447 HRESULT hrc = WINED3D_OK;
6449 TRACE("Relaying to swapchain\n");
6451 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6452 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6453 IWineD3DSwapChain_Release(swapchain);
6459 /** ********************************************************
6460 * Notification functions
6461 ** ********************************************************/
6462 /** This function must be called in the release of a resource when ref == 0,
6463 * the contents of resource must still be correct,
6464 * any handels to other resource held by the caller must be closed
6465 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6466 *****************************************************/
6467 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6469 ResourceList* resourceList;
6471 TRACE("(%p) : resource %p\n", This, resource);
6473 EnterCriticalSection(&resourceStoreCriticalSection);
6475 /* add a new texture to the frot of the linked list */
6476 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6477 resourceList->resource = resource;
6479 /* Get the old head */
6480 resourceList->next = This->resources;
6482 This->resources = resourceList;
6483 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6486 LeaveCriticalSection(&resourceStoreCriticalSection);
6491 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6493 ResourceList* resourceList = NULL;
6494 ResourceList* previousResourceList = NULL;
6496 TRACE("(%p) : resource %p\n", This, resource);
6499 EnterCriticalSection(&resourceStoreCriticalSection);
6501 resourceList = This->resources;
6503 while (resourceList != NULL) {
6504 if(resourceList->resource == resource) break;
6505 previousResourceList = resourceList;
6506 resourceList = resourceList->next;
6509 if (resourceList == NULL) {
6510 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6512 LeaveCriticalSection(&resourceStoreCriticalSection);
6516 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6518 /* make sure we don't leave a hole in the list */
6519 if (previousResourceList != NULL) {
6520 previousResourceList->next = resourceList->next;
6522 This->resources = resourceList->next;
6526 LeaveCriticalSection(&resourceStoreCriticalSection);
6532 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6536 TRACE("(%p) : resource %p\n", This, resource);
6537 switch(IWineD3DResource_GetType(resource)){
6538 case WINED3DRTYPE_SURFACE:
6539 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6541 case WINED3DRTYPE_TEXTURE:
6542 case WINED3DRTYPE_CUBETEXTURE:
6543 case WINED3DRTYPE_VOLUMETEXTURE:
6544 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6545 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6546 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6547 This->stateBlock->textures[counter] = NULL;
6549 if (This->updateStateBlock != This->stateBlock ){
6550 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6551 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6552 This->updateStateBlock->textures[counter] = NULL;
6557 case WINED3DRTYPE_VOLUME:
6558 /* TODO: nothing really? */
6560 case WINED3DRTYPE_VERTEXBUFFER:
6561 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6564 TRACE("Cleaning up stream pointers\n");
6566 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6567 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6568 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6570 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6571 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6572 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6573 This->updateStateBlock->streamSource[streamNumber] = 0;
6574 /* Set changed flag? */
6577 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) */
6578 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6579 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6580 This->stateBlock->streamSource[streamNumber] = 0;
6583 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6584 else { /* This shouldn't happen */
6585 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6592 case WINED3DRTYPE_INDEXBUFFER:
6593 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6594 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6595 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6596 This->updateStateBlock->pIndexData = NULL;
6599 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6600 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6601 This->stateBlock->pIndexData = NULL;
6607 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6612 /* Remove the resoruce from the resourceStore */
6613 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6615 TRACE("Resource released\n");
6619 /**********************************************************
6620 * IWineD3DDevice VTbl follows
6621 **********************************************************/
6623 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6625 /*** IUnknown methods ***/
6626 IWineD3DDeviceImpl_QueryInterface,
6627 IWineD3DDeviceImpl_AddRef,
6628 IWineD3DDeviceImpl_Release,
6629 /*** IWineD3DDevice methods ***/
6630 IWineD3DDeviceImpl_GetParent,
6631 /*** Creation methods**/
6632 IWineD3DDeviceImpl_CreateVertexBuffer,
6633 IWineD3DDeviceImpl_CreateIndexBuffer,
6634 IWineD3DDeviceImpl_CreateStateBlock,
6635 IWineD3DDeviceImpl_CreateSurface,
6636 IWineD3DDeviceImpl_CreateTexture,
6637 IWineD3DDeviceImpl_CreateVolumeTexture,
6638 IWineD3DDeviceImpl_CreateVolume,
6639 IWineD3DDeviceImpl_CreateCubeTexture,
6640 IWineD3DDeviceImpl_CreateQuery,
6641 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6642 IWineD3DDeviceImpl_CreateVertexDeclaration,
6643 IWineD3DDeviceImpl_CreateVertexShader,
6644 IWineD3DDeviceImpl_CreatePixelShader,
6645 IWineD3DDeviceImpl_CreatePalette,
6646 /*** Odd functions **/
6647 IWineD3DDeviceImpl_Init3D,
6648 IWineD3DDeviceImpl_Uninit3D,
6649 IWineD3DDeviceImpl_SetFullscreen,
6650 IWineD3DDeviceImpl_EnumDisplayModes,
6651 IWineD3DDeviceImpl_EvictManagedResources,
6652 IWineD3DDeviceImpl_GetAvailableTextureMem,
6653 IWineD3DDeviceImpl_GetBackBuffer,
6654 IWineD3DDeviceImpl_GetCreationParameters,
6655 IWineD3DDeviceImpl_GetDeviceCaps,
6656 IWineD3DDeviceImpl_GetDirect3D,
6657 IWineD3DDeviceImpl_GetDisplayMode,
6658 IWineD3DDeviceImpl_SetDisplayMode,
6659 IWineD3DDeviceImpl_GetHWND,
6660 IWineD3DDeviceImpl_SetHWND,
6661 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6662 IWineD3DDeviceImpl_GetRasterStatus,
6663 IWineD3DDeviceImpl_GetSwapChain,
6664 IWineD3DDeviceImpl_Reset,
6665 IWineD3DDeviceImpl_SetDialogBoxMode,
6666 IWineD3DDeviceImpl_SetCursorProperties,
6667 IWineD3DDeviceImpl_SetCursorPosition,
6668 IWineD3DDeviceImpl_ShowCursor,
6669 IWineD3DDeviceImpl_TestCooperativeLevel,
6670 /*** Getters and setters **/
6671 IWineD3DDeviceImpl_SetClipPlane,
6672 IWineD3DDeviceImpl_GetClipPlane,
6673 IWineD3DDeviceImpl_SetClipStatus,
6674 IWineD3DDeviceImpl_GetClipStatus,
6675 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6676 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6677 IWineD3DDeviceImpl_SetDepthStencilSurface,
6678 IWineD3DDeviceImpl_GetDepthStencilSurface,
6679 IWineD3DDeviceImpl_SetFVF,
6680 IWineD3DDeviceImpl_GetFVF,
6681 IWineD3DDeviceImpl_SetGammaRamp,
6682 IWineD3DDeviceImpl_GetGammaRamp,
6683 IWineD3DDeviceImpl_SetIndices,
6684 IWineD3DDeviceImpl_GetIndices,
6685 IWineD3DDeviceImpl_SetBasevertexIndex,
6686 IWineD3DDeviceImpl_SetLight,
6687 IWineD3DDeviceImpl_GetLight,
6688 IWineD3DDeviceImpl_SetLightEnable,
6689 IWineD3DDeviceImpl_GetLightEnable,
6690 IWineD3DDeviceImpl_SetMaterial,
6691 IWineD3DDeviceImpl_GetMaterial,
6692 IWineD3DDeviceImpl_SetNPatchMode,
6693 IWineD3DDeviceImpl_GetNPatchMode,
6694 IWineD3DDeviceImpl_SetPaletteEntries,
6695 IWineD3DDeviceImpl_GetPaletteEntries,
6696 IWineD3DDeviceImpl_SetPixelShader,
6697 IWineD3DDeviceImpl_GetPixelShader,
6698 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6699 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6700 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6701 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6702 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6703 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6704 IWineD3DDeviceImpl_SetRenderState,
6705 IWineD3DDeviceImpl_GetRenderState,
6706 IWineD3DDeviceImpl_SetRenderTarget,
6707 IWineD3DDeviceImpl_GetRenderTarget,
6708 IWineD3DDeviceImpl_SetFrontBackBuffers,
6709 IWineD3DDeviceImpl_SetSamplerState,
6710 IWineD3DDeviceImpl_GetSamplerState,
6711 IWineD3DDeviceImpl_SetScissorRect,
6712 IWineD3DDeviceImpl_GetScissorRect,
6713 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6714 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6715 IWineD3DDeviceImpl_SetStreamSource,
6716 IWineD3DDeviceImpl_GetStreamSource,
6717 IWineD3DDeviceImpl_SetStreamSourceFreq,
6718 IWineD3DDeviceImpl_GetStreamSourceFreq,
6719 IWineD3DDeviceImpl_SetTexture,
6720 IWineD3DDeviceImpl_GetTexture,
6721 IWineD3DDeviceImpl_SetTextureStageState,
6722 IWineD3DDeviceImpl_GetTextureStageState,
6723 IWineD3DDeviceImpl_SetTransform,
6724 IWineD3DDeviceImpl_GetTransform,
6725 IWineD3DDeviceImpl_SetVertexDeclaration,
6726 IWineD3DDeviceImpl_GetVertexDeclaration,
6727 IWineD3DDeviceImpl_SetVertexShader,
6728 IWineD3DDeviceImpl_GetVertexShader,
6729 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6730 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6731 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6732 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6733 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6734 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6735 IWineD3DDeviceImpl_SetViewport,
6736 IWineD3DDeviceImpl_GetViewport,
6737 IWineD3DDeviceImpl_MultiplyTransform,
6738 IWineD3DDeviceImpl_ValidateDevice,
6739 IWineD3DDeviceImpl_ProcessVertices,
6740 /*** State block ***/
6741 IWineD3DDeviceImpl_BeginStateBlock,
6742 IWineD3DDeviceImpl_EndStateBlock,
6743 /*** Scene management ***/
6744 IWineD3DDeviceImpl_BeginScene,
6745 IWineD3DDeviceImpl_EndScene,
6746 IWineD3DDeviceImpl_Present,
6747 IWineD3DDeviceImpl_Clear,
6749 IWineD3DDeviceImpl_DrawPrimitive,
6750 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6751 IWineD3DDeviceImpl_DrawPrimitiveUP,
6752 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6753 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6754 IWineD3DDeviceImpl_DrawRectPatch,
6755 IWineD3DDeviceImpl_DrawTriPatch,
6756 IWineD3DDeviceImpl_DeletePatch,
6757 IWineD3DDeviceImpl_ColorFill,
6758 IWineD3DDeviceImpl_UpdateTexture,
6759 IWineD3DDeviceImpl_UpdateSurface,
6760 IWineD3DDeviceImpl_GetRenderTargetData,
6761 IWineD3DDeviceImpl_GetFrontBufferData,
6762 /*** object tracking ***/
6763 IWineD3DDeviceImpl_ResourceReleased
6767 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6768 WINED3DRS_ALPHABLENDENABLE ,
6769 WINED3DRS_ALPHAFUNC ,
6770 WINED3DRS_ALPHAREF ,
6771 WINED3DRS_ALPHATESTENABLE ,
6773 WINED3DRS_COLORWRITEENABLE ,
6774 WINED3DRS_DESTBLEND ,
6775 WINED3DRS_DITHERENABLE ,
6776 WINED3DRS_FILLMODE ,
6777 WINED3DRS_FOGDENSITY ,
6779 WINED3DRS_FOGSTART ,
6780 WINED3DRS_LASTPIXEL ,
6781 WINED3DRS_SHADEMODE ,
6782 WINED3DRS_SRCBLEND ,
6783 WINED3DRS_STENCILENABLE ,
6784 WINED3DRS_STENCILFAIL ,
6785 WINED3DRS_STENCILFUNC ,
6786 WINED3DRS_STENCILMASK ,
6787 WINED3DRS_STENCILPASS ,
6788 WINED3DRS_STENCILREF ,
6789 WINED3DRS_STENCILWRITEMASK ,
6790 WINED3DRS_STENCILZFAIL ,
6791 WINED3DRS_TEXTUREFACTOR ,
6802 WINED3DRS_ZWRITEENABLE
6805 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6806 WINED3DTSS_ADDRESSW ,
6807 WINED3DTSS_ALPHAARG0 ,
6808 WINED3DTSS_ALPHAARG1 ,
6809 WINED3DTSS_ALPHAARG2 ,
6810 WINED3DTSS_ALPHAOP ,
6811 WINED3DTSS_BUMPENVLOFFSET ,
6812 WINED3DTSS_BUMPENVLSCALE ,
6813 WINED3DTSS_BUMPENVMAT00 ,
6814 WINED3DTSS_BUMPENVMAT01 ,
6815 WINED3DTSS_BUMPENVMAT10 ,
6816 WINED3DTSS_BUMPENVMAT11 ,
6817 WINED3DTSS_COLORARG0 ,
6818 WINED3DTSS_COLORARG1 ,
6819 WINED3DTSS_COLORARG2 ,
6820 WINED3DTSS_COLOROP ,
6821 WINED3DTSS_RESULTARG ,
6822 WINED3DTSS_TEXCOORDINDEX ,
6823 WINED3DTSS_TEXTURETRANSFORMFLAGS
6826 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6827 WINED3DSAMP_ADDRESSU ,
6828 WINED3DSAMP_ADDRESSV ,
6829 WINED3DSAMP_ADDRESSW ,
6830 WINED3DSAMP_BORDERCOLOR ,
6831 WINED3DSAMP_MAGFILTER ,
6832 WINED3DSAMP_MINFILTER ,
6833 WINED3DSAMP_MIPFILTER ,
6834 WINED3DSAMP_MIPMAPLODBIAS ,
6835 WINED3DSAMP_MAXMIPLEVEL ,
6836 WINED3DSAMP_MAXANISOTROPY ,
6837 WINED3DSAMP_SRGBTEXTURE ,
6838 WINED3DSAMP_ELEMENTINDEX
6841 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6843 WINED3DRS_AMBIENTMATERIALSOURCE ,
6844 WINED3DRS_CLIPPING ,
6845 WINED3DRS_CLIPPLANEENABLE ,
6846 WINED3DRS_COLORVERTEX ,
6847 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6848 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6849 WINED3DRS_FOGDENSITY ,
6851 WINED3DRS_FOGSTART ,
6852 WINED3DRS_FOGTABLEMODE ,
6853 WINED3DRS_FOGVERTEXMODE ,
6854 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6855 WINED3DRS_LIGHTING ,
6856 WINED3DRS_LOCALVIEWER ,
6857 WINED3DRS_MULTISAMPLEANTIALIAS ,
6858 WINED3DRS_MULTISAMPLEMASK ,
6859 WINED3DRS_NORMALIZENORMALS ,
6860 WINED3DRS_PATCHEDGESTYLE ,
6861 WINED3DRS_POINTSCALE_A ,
6862 WINED3DRS_POINTSCALE_B ,
6863 WINED3DRS_POINTSCALE_C ,
6864 WINED3DRS_POINTSCALEENABLE ,
6865 WINED3DRS_POINTSIZE ,
6866 WINED3DRS_POINTSIZE_MAX ,
6867 WINED3DRS_POINTSIZE_MIN ,
6868 WINED3DRS_POINTSPRITEENABLE ,
6869 WINED3DRS_RANGEFOGENABLE ,
6870 WINED3DRS_SPECULARMATERIALSOURCE ,
6871 WINED3DRS_TWEENFACTOR ,
6872 WINED3DRS_VERTEXBLEND
6875 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6876 WINED3DTSS_TEXCOORDINDEX ,
6877 WINED3DTSS_TEXTURETRANSFORMFLAGS
6880 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6881 WINED3DSAMP_DMAPOFFSET
6884 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6885 DWORD rep = StateTable[state].representative;
6889 if(!rep || isStateDirty(This, rep)) return;
6891 This->dirtyArray[This->numDirtyEntries++] = rep;
6894 This->isStateDirty[idx] |= (1 << shift);