wined3d: Misc comment updates.
[wine/wine64.git] / dlls / wined3d / device.c
blob333e79b31e63118df6f8c2169ca06066dcfb7d8f
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
82 /* helper macros */
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
91 object->ref = 1; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
100 object->ref = 1; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
122 *pp##type = NULL; \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
131 *pp##type = NULL; \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * GLSL helper functions follow
153 **********************************************************/
155 /** Detach the GLSL pixel or vertex shader object from the shader program */
156 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 if (shaderObj != 0 && programId != 0) {
161 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
162 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
163 checkGLcall("glDetachObjectARB");
167 /** Delete a GLSL shader program */
168 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 if (obj != 0) {
173 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
174 GL_EXTCALL(glDeleteObjectARB(obj));
175 checkGLcall("glDeleteObjectARB");
179 /** Delete the list of linked programs this shader is associated with.
180 * Also at this point, check to see if there are any objects left attached
181 * to each GLSL program. If not, delete the GLSL program object.
182 * This will be run when a device is released. */
183 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
185 struct list *ptr = NULL;
186 struct glsl_shader_prog_link *curLink = NULL;
187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
189 int numAttached = 0;
190 int i;
191 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
192 (one pixel shader and one vertex shader at most) */
194 ptr = list_head( &This->glsl_shader_progs );
195 while (ptr) {
196 /* First, get the current item,
197 * save the link to the next pointer,
198 * detach and delete shader objects,
199 * then de-allocate the list item's memory */
200 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
201 ptr = list_next( &This->glsl_shader_progs, ptr );
203 /* See if this object is still attached to the program - it may have been detached already */
204 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
205 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
206 for (i = 0; i < numAttached; i++) {
207 detach_glsl_shader(iface, objList[i], curLink->programId);
210 delete_glsl_shader_program(iface, curLink->programId);
212 /* Free the uniform locations */
213 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
214 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
216 /* Free the memory for this list item */
217 HeapFree(GetProcessHeap(), 0, curLink);
221 /**********************************************************
222 * IUnknown parts follows
223 **********************************************************/
225 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
229 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
230 if (IsEqualGUID(riid, &IID_IUnknown)
231 || IsEqualGUID(riid, &IID_IWineD3DBase)
232 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
233 IUnknown_AddRef(iface);
234 *ppobj = This;
235 return S_OK;
237 *ppobj = NULL;
238 return E_NOINTERFACE;
241 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
243 ULONG refCount = InterlockedIncrement(&This->ref);
245 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
246 return refCount;
249 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 ULONG refCount = InterlockedDecrement(&This->ref);
253 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
255 if (!refCount) {
256 if (This->fbo) {
257 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
260 HeapFree(GetProcessHeap(), 0, This->render_targets);
262 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
264 /* TODO: Clean up all the surfaces and textures! */
265 /* NOTE: You must release the parent if the object was created via a callback
266 ** ***************************/
268 /* Delete any GLSL shader programs that may exist */
269 if (This->vs_selected_mode == SHADER_GLSL ||
270 This->ps_selected_mode == SHADER_GLSL)
271 delete_glsl_shader_list(iface);
273 /* Release the update stateblock */
274 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
275 if(This->updateStateBlock != This->stateBlock)
276 FIXME("(%p) Something's still holding the Update stateblock\n",This);
278 This->updateStateBlock = NULL;
279 { /* because were not doing proper internal refcounts releasing the primary state block
280 causes recursion with the extra checks in ResourceReleased, to avoid this we have
281 to set this->stateBlock = NULL; first */
282 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
283 This->stateBlock = NULL;
285 /* Release the stateblock */
286 if(IWineD3DStateBlock_Release(stateBlock) > 0){
287 FIXME("(%p) Something's still holding the Update stateblock\n",This);
291 if (This->resources != NULL ) {
292 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
293 dumpResources(This->resources);
296 if(This->contexts) ERR("Context array not freed!\n");
298 IWineD3D_Release(This->wineD3D);
299 This->wineD3D = NULL;
300 HeapFree(GetProcessHeap(), 0, This);
301 TRACE("Freed device %p\n", This);
302 This = NULL;
304 return refCount;
307 /**********************************************************
308 * IWineD3DDevice implementation follows
309 **********************************************************/
310 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 *pParent = This->parent;
313 IUnknown_AddRef(This->parent);
314 return WINED3D_OK;
317 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
318 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
319 GLenum error, glUsage;
320 DWORD vboUsage = object->resource.usage;
321 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
322 WARN("Creating a vbo failed once, not trying again\n");
323 return;
326 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
328 ENTER_GL();
329 /* Make sure that the gl error is cleared. Do not use checkGLcall
330 * here because checkGLcall just prints a fixme and continues. However,
331 * if an error during VBO creation occurs we can fall back to non-vbo operation
332 * with full functionality(but performance loss)
334 while(glGetError() != GL_NO_ERROR);
336 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
337 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
338 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
339 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
340 * to check if the rhw and color values are in the correct format.
343 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
344 error = glGetError();
345 if(object->vbo == 0 || error != GL_NO_ERROR) {
346 WARN("Failed to create a VBO with error %d\n", error);
347 goto error;
350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
351 error = glGetError();
352 if(error != GL_NO_ERROR) {
353 WARN("Failed to bind the VBO, error %d\n", error);
354 goto error;
357 /* Don't use static, because dx apps tend to update the buffer
358 * quite often even if they specify 0 usage. Because we always keep the local copy
359 * we never read from the vbo and can create a write only opengl buffer.
361 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
362 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
363 case WINED3DUSAGE_DYNAMIC:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage = GL_STREAM_DRAW_ARB;
366 break;
367 case WINED3DUSAGE_WRITEONLY:
368 default:
369 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
370 glUsage = GL_DYNAMIC_DRAW_ARB;
371 break;
374 /* Reserve memory for the buffer. The amount of data won't change
375 * so we are safe with calling glBufferData once with a NULL ptr and
376 * calling glBufferSubData on updates
378 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
379 error = glGetError();
380 if(error != GL_NO_ERROR) {
381 WARN("glBufferDataARB failed with error %d\n", error);
382 goto error;
385 LEAVE_GL();
387 return;
388 error:
389 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
390 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
391 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
392 object->vbo = 0;
393 object->Flags |= VBFLAG_VBOCREATEFAIL;
394 LEAVE_GL();
395 return;
398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
399 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
400 IUnknown *parent) {
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 IWineD3DVertexBufferImpl *object;
403 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
404 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
405 BOOL conv;
407 if(Size == 0) {
408 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
409 *ppVertexBuffer = NULL;
410 return WINED3DERR_INVALIDCALL;
413 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
415 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
416 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
418 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
419 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
421 object->fvf = FVF;
423 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
424 * drawStridedFast (half-life 2).
426 * Basically converting the vertices in the buffer is quite expensive, and observations
427 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
428 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
430 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
431 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
432 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
433 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
434 * dx7 apps.
435 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
436 * more. In this call we can convert dx7 buffers too.
438 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
439 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
440 (dxVersion > 7 || !conv) ) {
441 CreateVBO(object);
443 return WINED3D_OK;
446 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
447 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
448 HANDLE *sharedHandle, IUnknown *parent) {
449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
450 IWineD3DIndexBufferImpl *object;
451 TRACE("(%p) Creating index buffer\n", This);
453 /* Allocate the storage for the device */
454 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
456 /*TODO: use VBO's */
457 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
458 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
461 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
462 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
463 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
465 return WINED3D_OK;
468 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
471 IWineD3DStateBlockImpl *object;
472 int i, j;
473 HRESULT temp_result;
475 D3DCREATEOBJECTINSTANCE(object, StateBlock)
476 object->blockType = Type;
478 for(i = 0; i < LIGHTMAP_SIZE; i++) {
479 list_init(&object->lightMap[i]);
482 /* Special case - Used during initialization to produce a placeholder stateblock
483 so other functions called can update a state block */
484 if (Type == WINED3DSBT_INIT) {
485 /* Don't bother increasing the reference count otherwise a device will never
486 be freed due to circular dependencies */
487 return WINED3D_OK;
490 temp_result = allocate_shader_constants(object);
491 if (WINED3D_OK != temp_result)
492 return temp_result;
494 /* Otherwise, might as well set the whole state block to the appropriate values */
495 if (This->stateBlock != NULL)
496 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
497 else
498 memset(object->streamFreq, 1, sizeof(object->streamFreq));
500 /* Reset the ref and type after kludging it */
501 object->wineD3DDevice = This;
502 object->ref = 1;
503 object->blockType = Type;
505 TRACE("Updating changed flags appropriate for type %d\n", Type);
507 if (Type == WINED3DSBT_ALL) {
509 TRACE("ALL => Pretend everything has changed\n");
510 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
512 /* Lights are not part of the changed / set structure */
513 for(j = 0; j < LIGHTMAP_SIZE; j++) {
514 struct list *e;
515 LIST_FOR_EACH(e, &object->lightMap[j]) {
516 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
517 light->changed = TRUE;
518 light->enabledChanged = TRUE;
521 } else if (Type == WINED3DSBT_PIXELSTATE) {
523 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
524 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
526 object->changed.pixelShader = TRUE;
528 /* Pixel Shader Constants */
529 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
530 object->changed.pixelShaderConstantsF[i] = TRUE;
531 for (i = 0; i < MAX_CONST_B; ++i)
532 object->changed.pixelShaderConstantsB[i] = TRUE;
533 for (i = 0; i < MAX_CONST_I; ++i)
534 object->changed.pixelShaderConstantsI[i] = TRUE;
536 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
537 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
539 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
540 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
541 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
544 for (j = 0 ; j < 16; j++) {
545 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
547 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
551 } else if (Type == WINED3DSBT_VERTEXSTATE) {
553 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
554 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
556 object->changed.vertexShader = TRUE;
558 /* Vertex Shader Constants */
559 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
560 object->changed.vertexShaderConstantsF[i] = TRUE;
561 for (i = 0; i < MAX_CONST_B; ++i)
562 object->changed.vertexShaderConstantsB[i] = TRUE;
563 for (i = 0; i < MAX_CONST_I; ++i)
564 object->changed.vertexShaderConstantsI[i] = TRUE;
566 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
567 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
569 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
570 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
571 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
574 for (j = 0 ; j < 16; j++){
575 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
576 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
580 for(j = 0; j < LIGHTMAP_SIZE; j++) {
581 struct list *e;
582 LIST_FOR_EACH(e, &object->lightMap[j]) {
583 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
584 light->changed = TRUE;
585 light->enabledChanged = TRUE;
588 } else {
589 FIXME("Unrecognized state block type %d\n", Type);
592 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
593 return WINED3D_OK;
597 /* ************************************
598 MSDN:
599 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
601 Discard
602 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
604 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.
606 ******************************** */
608 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) {
609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
610 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
611 unsigned int pow2Width, pow2Height;
612 unsigned int Size = 1;
613 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
614 TRACE("(%p) Create surface\n",This);
616 /** FIXME: Check ranges on the inputs are valid
617 * MSDN
618 * MultisampleQuality
619 * [in] Quality level. The valid range is between zero and one less than the level
620 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
621 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
622 * values of paired render targets, depth stencil surfaces, and the MultiSample type
623 * must all match.
624 *******************************/
628 * TODO: Discard MSDN
629 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 * If this flag is set, the contents of the depth stencil buffer will be
632 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
633 * with a different depth surface.
635 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
636 ***************************/
638 if(MultisampleQuality < 0) {
639 FIXME("Invalid multisample level %d\n", MultisampleQuality);
640 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
643 if(MultisampleQuality > 0) {
644 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
645 MultisampleQuality=0;
648 /** FIXME: Check that the format is supported
649 * by the device.
650 *******************************/
652 /* Non-power2 support */
653 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
654 pow2Width = Width;
655 pow2Height = Height;
656 } else {
657 /* Find the nearest pow2 match */
658 pow2Width = pow2Height = 1;
659 while (pow2Width < Width) pow2Width <<= 1;
660 while (pow2Height < Height) pow2Height <<= 1;
663 if (pow2Width > Width || pow2Height > Height) {
664 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
665 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
666 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
667 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
668 This, Width, Height);
669 return WINED3DERR_NOTAVAILABLE;
673 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
674 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
675 * space!
676 *********************************/
677 if (WINED3DFMT_UNKNOWN == Format) {
678 Size = 0;
679 } else if (Format == WINED3DFMT_DXT1) {
680 /* DXT1 is half byte per pixel */
681 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
683 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
684 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
685 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
686 } else {
687 /* The pitch is a multiple of 4 bytes */
688 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
689 Size *= Height;
692 /** Create and initialise the surface resource **/
693 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
694 /* "Standalone" surface */
695 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
697 object->currentDesc.Width = Width;
698 object->currentDesc.Height = Height;
699 object->currentDesc.MultiSampleType = MultiSample;
700 object->currentDesc.MultiSampleQuality = MultisampleQuality;
702 /* Setup some glformat defaults */
703 object->glDescription.glFormat = tableEntry->glFormat;
704 object->glDescription.glFormatInternal = tableEntry->glInternal;
705 object->glDescription.glType = tableEntry->glType;
707 object->glDescription.textureName = 0;
708 object->glDescription.level = Level;
709 object->glDescription.target = GL_TEXTURE_2D;
711 /* Internal data */
712 object->pow2Width = pow2Width;
713 object->pow2Height = pow2Height;
715 /* Flags */
716 object->Flags = 0; /* We start without flags set */
717 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
718 object->Flags |= Discard ? SFLAG_DISCARD : 0;
719 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
720 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
723 if (WINED3DFMT_UNKNOWN != Format) {
724 object->bytesPerPixel = tableEntry->bpp;
725 } else {
726 object->bytesPerPixel = 0;
729 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
731 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
733 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
734 * this function is too deep to need to care about things like this.
735 * Levels need to be checked too, and possibly Type since they all affect what can be done.
736 * ****************************************/
737 switch(Pool) {
738 case WINED3DPOOL_SCRATCH:
739 if(!Lockable)
740 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
741 "which are mutually exclusive, setting lockable to TRUE\n");
742 Lockable = TRUE;
743 break;
744 case WINED3DPOOL_SYSTEMMEM:
745 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
746 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
747 case WINED3DPOOL_MANAGED:
748 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
749 "Usage of DYNAMIC which are mutually exclusive, not doing "
750 "anything just telling you.\n");
751 break;
752 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
753 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
754 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
755 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
756 break;
757 default:
758 FIXME("(%p) Unknown pool %d\n", This, Pool);
759 break;
762 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
763 FIXME("Trying to create a render target that isn't in the default pool\n");
766 /* mark the texture as dirty so that it gets loaded first time around*/
767 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
768 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
769 This, Width, Height, Format, debug_d3dformat(Format),
770 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
772 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
773 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
774 This->ddraw_primary = (IWineD3DSurface *) object;
776 /* Look at the implementation and set the correct Vtable */
777 switch(Impl) {
778 case SURFACE_OPENGL:
779 /* Nothing to do, it's set already */
780 break;
782 case SURFACE_GDI:
783 object->lpVtbl = &IWineGDISurface_Vtbl;
784 break;
786 default:
787 /* To be sure to catch this */
788 ERR("Unknown requested surface implementation %d!\n", Impl);
789 IWineD3DSurface_Release((IWineD3DSurface *) object);
790 return WINED3DERR_INVALIDCALL;
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
798 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
799 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
800 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804 IWineD3DTextureImpl *object;
805 unsigned int i;
806 UINT tmpW;
807 UINT tmpH;
808 HRESULT hr;
809 unsigned int pow2Width;
810 unsigned int pow2Height;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN >= Format) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
821 return WINED3DERR_INVALIDCALL;
824 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
825 D3DINITIALIZEBASETEXTURE(object->baseTexture);
826 object->width = Width;
827 object->height = Height;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
831 pow2Width = Width;
832 pow2Height = Height;
833 } else {
834 /* Find the nearest pow2 match */
835 pow2Width = pow2Height = 1;
836 while (pow2Width < Width) pow2Width <<= 1;
837 while (pow2Height < Height) pow2Height <<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
843 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
844 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
846 /* Calculate levels for mip mapping */
847 if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
850 tmpW = Width;
851 tmpH = Height;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
861 tmpW = Width;
862 tmpH = Height;
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
869 /* clean up */
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
873 *ppTexture = NULL;
874 return hr;
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
884 TRACE("(%p) : Created texture %p\n", This, object);
885 return WINED3D_OK;
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 UINT Levels, DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolumeTexture **ppVolumeTexture,
893 HANDLE *pSharedHandle, IUnknown *parent,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 IWineD3DVolumeTextureImpl *object;
898 unsigned int i;
899 UINT tmpW;
900 UINT tmpH;
901 UINT tmpD;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN >= Format) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
907 return WINED3DERR_INVALIDCALL;
910 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
911 D3DINITIALIZEBASETEXTURE(object->baseTexture);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
914 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
916 object->width = Width;
917 object->height = Height;
918 object->depth = Depth;
920 /* Calculate levels for mip mapping */
921 if (Levels == 0) {
922 object->baseTexture.levels++;
923 tmpW = Width;
924 tmpH = Height;
925 tmpD = Depth;
926 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 tmpD = max(1, tmpD >> 1);
930 object->baseTexture.levels++;
932 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
935 /* Generate all the surfaces */
936 tmpW = Width;
937 tmpH = Height;
938 tmpD = Depth;
940 for (i = 0; i < object->baseTexture.levels; i++)
942 HRESULT hr;
943 /* Create the volume */
944 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
945 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
947 if(FAILED(hr)) {
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
950 *ppVolumeTexture = NULL;
951 return hr;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
957 /* calcualte the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
960 tmpD = max(1, tmpD >> 1);
963 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
964 TRACE("(%p) : Created volume texture %p\n", This, object);
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
969 UINT Width, UINT Height, UINT Depth,
970 DWORD Usage,
971 WINED3DFORMAT Format, WINED3DPOOL Pool,
972 IWineD3DVolume** ppVolume,
973 HANDLE* pSharedHandle, IUnknown *parent) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
977 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
979 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
982 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
984 object->currentDesc.Width = Width;
985 object->currentDesc.Height = Height;
986 object->currentDesc.Depth = Depth;
987 object->bytesPerPixel = formatDesc->bpp;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object->lockable = TRUE;
991 object->locked = FALSE;
992 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
993 object->dirty = TRUE;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
998 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
999 UINT Levels, DWORD Usage,
1000 WINED3DFORMAT Format, WINED3DPOOL Pool,
1001 IWineD3DCubeTexture **ppCubeTexture,
1002 HANDLE *pSharedHandle, IUnknown *parent,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1007 unsigned int i, j;
1008 UINT tmpW;
1009 HRESULT hr;
1010 unsigned int pow2EdgeLength = EdgeLength;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN >= Format) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1016 return WINED3DERR_INVALIDCALL;
1019 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1020 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1022 TRACE("(%p) Create Cube Texture\n", This);
1024 /** Non-power2 support **/
1026 /* Find the nearest pow2 match */
1027 pow2EdgeLength = 1;
1028 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1030 object->edgeLength = EdgeLength;
1031 /* TODO: support for native non-power 2 */
1032 /* Precalculated scaling for 'faked' non power of two texture coords */
1033 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1035 /* Calculate levels for mip mapping */
1036 if (Levels == 0) {
1037 object->baseTexture.levels++;
1038 tmpW = EdgeLength;
1039 while (tmpW > 1) {
1040 tmpW = max(1, tmpW >> 1);
1041 object->baseTexture.levels++;
1043 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1046 /* Generate all the surfaces */
1047 tmpW = EdgeLength;
1048 for (i = 0; i < object->baseTexture.levels; i++) {
1050 /* Create the 6 faces */
1051 for (j = 0; j < 6; j++) {
1053 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1054 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1056 if(hr!= WINED3D_OK) {
1057 /* clean up */
1058 int k;
1059 int l;
1060 for (l = 0; l < j; l++) {
1061 IWineD3DSurface_Release(object->surfaces[j][i]);
1063 for (k = 0; k < i; k++) {
1064 for (l = 0; l < 6; l++) {
1065 IWineD3DSurface_Release(object->surfaces[l][j]);
1069 FIXME("(%p) Failed to create surface\n",object);
1070 HeapFree(GetProcessHeap(),0,object);
1071 *ppCubeTexture = NULL;
1072 return hr;
1074 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1075 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1077 tmpW = max(1, tmpW >> 1);
1080 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1081 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1082 return WINED3D_OK;
1085 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1087 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1088 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1090 /* Just a check to see if we support this type of query */
1091 switch(Type) {
1092 case WINED3DQUERYTYPE_OCCLUSION:
1093 TRACE("(%p) occlusion query\n", This);
1094 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1095 hr = WINED3D_OK;
1096 else
1097 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1098 break;
1100 case WINED3DQUERYTYPE_EVENT:
1101 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1102 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1104 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1105 hr = WINED3D_OK;
1106 break;
1108 case WINED3DQUERYTYPE_VCACHE:
1109 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1110 case WINED3DQUERYTYPE_VERTEXSTATS:
1111 case WINED3DQUERYTYPE_TIMESTAMP:
1112 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1113 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1114 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1115 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1116 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1117 case WINED3DQUERYTYPE_PIXELTIMINGS:
1118 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1119 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1120 default:
1121 FIXME("(%p) Unhandled query type %d\n", This, Type);
1123 if(NULL == ppQuery || hr != WINED3D_OK) {
1124 return hr;
1127 D3DCREATEOBJECTINSTANCE(object, Query)
1128 object->type = Type;
1129 /* allocated the 'extended' data based on the type of query requested */
1130 switch(Type){
1131 case WINED3DQUERYTYPE_OCCLUSION:
1132 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1133 TRACE("(%p) Allocating data for an occlusion query\n", This);
1134 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1135 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1136 break;
1138 case WINED3DQUERYTYPE_VCACHE:
1139 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1140 case WINED3DQUERYTYPE_VERTEXSTATS:
1141 case WINED3DQUERYTYPE_EVENT:
1142 case WINED3DQUERYTYPE_TIMESTAMP:
1143 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1144 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1145 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1146 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1147 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1148 case WINED3DQUERYTYPE_PIXELTIMINGS:
1149 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1150 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1151 default:
1152 object->extendedData = 0;
1153 FIXME("(%p) Unhandled query type %d\n",This , Type);
1155 TRACE("(%p) : Created Query %p\n", This, object);
1156 return WINED3D_OK;
1159 /*****************************************************************************
1160 * IWineD3DDeviceImpl_SetupFullscreenWindow
1162 * Helper function that modifies a HWND's Style and ExStyle for proper
1163 * fullscreen use.
1165 * Params:
1166 * iface: Pointer to the IWineD3DDevice interface
1167 * window: Window to setup
1169 *****************************************************************************/
1170 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1173 LONG style, exStyle;
1174 /* Don't do anything if an original style is stored.
1175 * That shouldn't happen
1177 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1178 if (This->style || This->exStyle) {
1179 ERR("(%p): Want to change the window parameters of HWND %p, but "
1180 "another style is stored for restoration afterwards\n", This, window);
1183 /* Get the parameters and save them */
1184 style = GetWindowLongW(window, GWL_STYLE);
1185 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1186 This->style = style;
1187 This->exStyle = exStyle;
1189 /* Filter out window decorations */
1190 style &= ~WS_CAPTION;
1191 style &= ~WS_THICKFRAME;
1192 exStyle &= ~WS_EX_WINDOWEDGE;
1193 exStyle &= ~WS_EX_CLIENTEDGE;
1195 /* Make sure the window is managed, otherwise we won't get keyboard input */
1196 style |= WS_POPUP | WS_SYSMENU;
1198 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1199 This->style, This->exStyle, style, exStyle);
1201 SetWindowLongW(window, GWL_STYLE, style);
1202 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1204 /* Inform the window about the update. */
1205 SetWindowPos(window, HWND_TOP, 0, 0,
1206 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1207 ShowWindow(window, TRUE);
1210 /*****************************************************************************
1211 * IWineD3DDeviceImpl_RestoreWindow
1213 * Helper function that restores a windows' properties when taking it out
1214 * of fullscreen mode
1216 * Params:
1217 * iface: Pointer to the IWineD3DDevice interface
1218 * window: Window to setup
1220 *****************************************************************************/
1221 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1224 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1225 * switch, do nothing
1227 if (!This->style && !This->exStyle) return;
1229 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1230 This, window, This->style, This->exStyle);
1232 SetWindowLongW(window, GWL_STYLE, This->style);
1233 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1235 /* Delete the old values */
1236 This->style = 0;
1237 This->exStyle = 0;
1239 /* Inform the window about the update */
1240 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1241 0, 0, 0, 0, /* Pos, Size, ignored */
1242 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1245 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1246 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1247 IUnknown* parent,
1248 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1249 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1252 HDC hDc;
1253 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1254 HRESULT hr = WINED3D_OK;
1255 IUnknown *bufferParent;
1256 Display *display;
1258 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1260 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1261 * does a device hold a reference to a swap chain giving them a lifetime of the device
1262 * or does the swap chain notify the device of its destruction.
1263 *******************************/
1265 /* Check the params */
1266 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1267 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1268 return WINED3DERR_INVALIDCALL;
1269 } else if (pPresentationParameters->BackBufferCount > 1) {
1270 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");
1273 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1275 /*********************
1276 * Lookup the window Handle and the relating X window handle
1277 ********************/
1279 /* Setup hwnd we are using, plus which display this equates to */
1280 object->win_handle = pPresentationParameters->hDeviceWindow;
1281 if (!object->win_handle) {
1282 object->win_handle = This->createParms.hFocusWindow;
1285 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1286 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1287 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1288 return WINED3DERR_NOTAVAILABLE;
1290 hDc = GetDC(object->win_handle);
1291 display = get_display(hDc);
1292 ReleaseDC(object->win_handle, hDc);
1293 TRACE("Using a display of %p %p\n", display, hDc);
1295 if (NULL == display || NULL == hDc) {
1296 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1297 return WINED3DERR_NOTAVAILABLE;
1300 if (object->win == 0) {
1301 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1302 return WINED3DERR_NOTAVAILABLE;
1305 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1306 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1307 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1309 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1310 * then the corresponding dimension of the client area of the hDeviceWindow
1311 * (or the focus window, if hDeviceWindow is NULL) is taken.
1312 **********************/
1314 if (pPresentationParameters->Windowed &&
1315 ((pPresentationParameters->BackBufferWidth == 0) ||
1316 (pPresentationParameters->BackBufferHeight == 0))) {
1318 RECT Rect;
1319 GetClientRect(object->win_handle, &Rect);
1321 if (pPresentationParameters->BackBufferWidth == 0) {
1322 pPresentationParameters->BackBufferWidth = Rect.right;
1323 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1325 if (pPresentationParameters->BackBufferHeight == 0) {
1326 pPresentationParameters->BackBufferHeight = Rect.bottom;
1327 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1331 /* Put the correct figures in the presentation parameters */
1332 TRACE("Copying across presentation parameters\n");
1333 object->presentParms = *pPresentationParameters;
1335 TRACE("calling rendertarget CB\n");
1336 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1337 parent,
1338 object->presentParms.BackBufferWidth,
1339 object->presentParms.BackBufferHeight,
1340 object->presentParms.BackBufferFormat,
1341 object->presentParms.MultiSampleType,
1342 object->presentParms.MultiSampleQuality,
1343 TRUE /* Lockable */,
1344 &object->frontBuffer,
1345 NULL /* pShared (always null)*/);
1346 if (object->frontBuffer != NULL) {
1347 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1348 } else {
1349 ERR("Failed to create the front buffer\n");
1350 goto error;
1354 * Create an opengl context for the display visual
1355 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1356 * use different properties after that point in time. FIXME: How to handle when requested format
1357 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1358 * it chooses is identical to the one already being used!
1359 **********************************/
1361 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1362 ENTER_GL();
1363 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1364 LEAVE_GL();
1366 if (!object->context) {
1367 ERR("Failed to create a new context\n");
1368 hr = WINED3DERR_NOTAVAILABLE;
1369 goto error;
1370 } else {
1371 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1372 object->win_handle, object->context->glCtx, object->win);
1375 /*********************
1376 * Windowed / Fullscreen
1377 *******************/
1380 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1381 * so we should really check to see if there is a fullscreen swapchain already
1382 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1383 **************************************/
1385 if (!pPresentationParameters->Windowed) {
1387 DEVMODEW devmode;
1388 HDC hdc;
1389 int bpp = 0;
1390 RECT clip_rc;
1392 /* Get info on the current display setup */
1393 hdc = GetDC(0);
1394 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1395 ReleaseDC(0, hdc);
1397 /* Change the display settings */
1398 memset(&devmode, 0, sizeof(DEVMODEW));
1399 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1400 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1401 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1402 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1403 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1404 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1406 /* For GetDisplayMode */
1407 This->ddraw_width = devmode.dmPelsWidth;
1408 This->ddraw_height = devmode.dmPelsHeight;
1409 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1411 IWineD3DDevice_SetFullscreen(iface, TRUE);
1413 /* And finally clip mouse to our screen */
1414 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1415 ClipCursor(&clip_rc);
1418 /*********************
1419 * Create the back, front and stencil buffers
1420 *******************/
1421 if(object->presentParms.BackBufferCount > 0) {
1422 int i;
1424 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1425 if(!object->backBuffer) {
1426 ERR("Out of memory\n");
1427 hr = E_OUTOFMEMORY;
1428 goto error;
1431 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1432 TRACE("calling rendertarget CB\n");
1433 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1434 parent,
1435 object->presentParms.BackBufferWidth,
1436 object->presentParms.BackBufferHeight,
1437 object->presentParms.BackBufferFormat,
1438 object->presentParms.MultiSampleType,
1439 object->presentParms.MultiSampleQuality,
1440 TRUE /* Lockable */,
1441 &object->backBuffer[i],
1442 NULL /* pShared (always null)*/);
1443 if(hr == WINED3D_OK && object->backBuffer[i]) {
1444 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1445 } else {
1446 ERR("Cannot create new back buffer\n");
1447 goto error;
1449 ENTER_GL();
1450 glDrawBuffer(GL_BACK);
1451 checkGLcall("glDrawBuffer(GL_BACK)");
1452 LEAVE_GL();
1454 } else {
1455 object->backBuffer = NULL;
1457 /* Single buffering - draw to front buffer */
1458 ENTER_GL();
1459 glDrawBuffer(GL_FRONT);
1460 checkGLcall("glDrawBuffer(GL_FRONT)");
1461 LEAVE_GL();
1464 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1465 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1466 TRACE("Creating depth stencil buffer\n");
1467 if (This->depthStencilBuffer == NULL ) {
1468 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1469 parent,
1470 object->presentParms.BackBufferWidth,
1471 object->presentParms.BackBufferHeight,
1472 object->presentParms.AutoDepthStencilFormat,
1473 object->presentParms.MultiSampleType,
1474 object->presentParms.MultiSampleQuality,
1475 FALSE /* FIXME: Discard */,
1476 &This->depthStencilBuffer,
1477 NULL /* pShared (always null)*/ );
1478 if (This->depthStencilBuffer != NULL)
1479 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1482 /** TODO: A check on width, height and multisample types
1483 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1484 ****************************/
1485 object->wantsDepthStencilBuffer = TRUE;
1486 } else {
1487 object->wantsDepthStencilBuffer = FALSE;
1490 TRACE("Created swapchain %p\n", object);
1491 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1492 return WINED3D_OK;
1494 error:
1495 if (object->backBuffer) {
1496 int i;
1497 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1498 if(object->backBuffer[i]) {
1499 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1500 IUnknown_Release(bufferParent); /* once for the get parent */
1501 if (IUnknown_Release(bufferParent) > 0) {
1502 FIXME("(%p) Something's still holding the back buffer\n",This);
1506 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1507 object->backBuffer = NULL;
1509 if(object->context) {
1510 DestroyContext(This, object->context);
1512 if(object->frontBuffer) {
1513 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1514 IUnknown_Release(bufferParent); /* once for the get parent */
1515 if (IUnknown_Release(bufferParent) > 0) {
1516 FIXME("(%p) Something's still holding the front buffer\n",This);
1519 if(object) HeapFree(GetProcessHeap(), 0, object);
1520 return hr;
1523 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1524 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1526 TRACE("(%p)\n", This);
1528 return This->NumberOfSwapChains;
1531 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1533 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1535 if(iSwapChain < This->NumberOfSwapChains) {
1536 *pSwapChain = This->swapchains[iSwapChain];
1537 IWineD3DSwapChain_AddRef(*pSwapChain);
1538 TRACE("(%p) returning %p\n", This, *pSwapChain);
1539 return WINED3D_OK;
1540 } else {
1541 TRACE("Swapchain out of range\n");
1542 *pSwapChain = NULL;
1543 return WINED3DERR_INVALIDCALL;
1547 /*****
1548 * Vertex Declaration
1549 *****/
1550 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1551 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1553 IWineD3DVertexDeclarationImpl *object = NULL;
1554 HRESULT hr = WINED3D_OK;
1556 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1557 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1559 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1560 object->allFVF = 0;
1562 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1564 return hr;
1567 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1568 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1570 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1571 HRESULT hr = WINED3D_OK;
1572 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1573 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1575 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1577 if (vertex_declaration) {
1578 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1581 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1583 if (WINED3D_OK != hr) {
1584 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1585 IWineD3DVertexShader_Release(*ppVertexShader);
1586 return WINED3DERR_INVALIDCALL;
1589 return WINED3D_OK;
1592 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1594 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1595 HRESULT hr = WINED3D_OK;
1597 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1598 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1599 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1600 if (WINED3D_OK == hr) {
1601 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1602 } else {
1603 WARN("(%p) : Failed to create pixel shader\n", This);
1606 return hr;
1609 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1611 IWineD3DPaletteImpl *object;
1612 HRESULT hr;
1613 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1615 /* Create the new object */
1616 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1617 if(!object) {
1618 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1619 return E_OUTOFMEMORY;
1622 object->lpVtbl = &IWineD3DPalette_Vtbl;
1623 object->ref = 1;
1624 object->Flags = Flags;
1625 object->parent = Parent;
1626 object->wineD3DDevice = This;
1627 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1629 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1631 if(!object->hpal) {
1632 HeapFree( GetProcessHeap(), 0, object);
1633 return E_OUTOFMEMORY;
1636 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1637 if(FAILED(hr)) {
1638 IWineD3DPalette_Release((IWineD3DPalette *) object);
1639 return hr;
1642 *Palette = (IWineD3DPalette *) object;
1644 return WINED3D_OK;
1647 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1649 IWineD3DSwapChainImpl *swapchain;
1650 DWORD state;
1652 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1653 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1655 /* TODO: Test if OpenGL is compiled in and loaded */
1657 /* Initialize the texture unit mapping to a 1:1 mapping */
1658 for(state = 0; state < MAX_SAMPLERS; state++) {
1659 This->texUnitMap[state] = state;
1661 This->oneToOneTexUnitMap = TRUE;
1663 /* Setup the implicit swapchain */
1664 TRACE("Creating implicit swapchain\n");
1665 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1666 WARN("Failed to create implicit swapchain\n");
1667 return WINED3DERR_INVALIDCALL;
1670 This->NumberOfSwapChains = 1;
1671 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1672 if(!This->swapchains) {
1673 ERR("Out of memory!\n");
1674 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1675 return E_OUTOFMEMORY;
1677 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1679 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1681 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1682 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1683 This->render_targets[0] = swapchain->backBuffer[0];
1684 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1686 else {
1687 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1688 This->render_targets[0] = swapchain->frontBuffer;
1689 This->lastActiveRenderTarget = swapchain->frontBuffer;
1691 IWineD3DSurface_AddRef(This->render_targets[0]);
1692 This->activeContext = swapchain->context;
1694 /* Depth Stencil support */
1695 This->stencilBufferTarget = This->depthStencilBuffer;
1696 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1697 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1699 if (NULL != This->stencilBufferTarget) {
1700 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1703 /* Set up some starting GL setup */
1704 ENTER_GL();
1706 * Initialize openGL extension related variables
1707 * with Default values
1710 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1711 /* Setup all the devices defaults */
1712 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1713 #if 0
1714 IWineD3DImpl_CheckGraphicsMemory();
1715 #endif
1717 /* Initialize our list of GLSL programs */
1718 list_init(&This->glsl_shader_progs);
1720 { /* Set a default viewport */
1721 WINED3DVIEWPORT vp;
1722 vp.X = 0;
1723 vp.Y = 0;
1724 vp.Width = pPresentationParameters->BackBufferWidth;
1725 vp.Height = pPresentationParameters->BackBufferHeight;
1726 vp.MinZ = 0.0f;
1727 vp.MaxZ = 1.0f;
1728 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1731 /* Initialize the current view state */
1732 This->view_ident = 1;
1733 This->contexts[0]->last_was_rhw = 0;
1734 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1735 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1736 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1737 LEAVE_GL();
1739 /* Clear the screen */
1740 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1742 This->d3d_initialized = TRUE;
1743 return WINED3D_OK;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1748 int sampler;
1749 uint i;
1750 TRACE("(%p)\n", This);
1752 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1754 /* Delete the pbuffer context if there is any */
1755 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1757 /* Delete the mouse cursor texture */
1758 if(This->cursorTexture) {
1759 ENTER_GL();
1760 glDeleteTextures(1, &This->cursorTexture);
1761 LEAVE_GL();
1762 This->cursorTexture = 0;
1765 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1766 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1769 /* Release the buffers (with sanity checks)*/
1770 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1771 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1772 if(This->depthStencilBuffer != This->stencilBufferTarget)
1773 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1775 This->stencilBufferTarget = NULL;
1777 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1778 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1779 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1781 TRACE("Setting rendertarget to NULL\n");
1782 This->render_targets[0] = NULL;
1784 if (This->depthStencilBuffer) {
1785 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1786 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1788 This->depthStencilBuffer = NULL;
1791 for(i=0; i < This->NumberOfSwapChains; i++) {
1792 TRACE("Releasing the implicit swapchain %d\n", i);
1793 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1794 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1798 HeapFree(GetProcessHeap(), 0, This->swapchains);
1799 This->swapchains = NULL;
1800 This->NumberOfSwapChains = 0;
1802 This->d3d_initialized = FALSE;
1803 return WINED3D_OK;
1806 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1808 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1810 /* Setup the window for fullscreen mode */
1811 if(fullscreen && !This->ddraw_fullscreen) {
1812 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1813 } else if(!fullscreen && This->ddraw_fullscreen) {
1814 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1817 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1818 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1819 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1820 * separately.
1822 This->ddraw_fullscreen = fullscreen;
1825 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1826 DEVMODEW devmode;
1827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1828 LONG ret;
1829 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1830 RECT clip_rc;
1832 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1834 /* Resize the screen even without a window:
1835 * The app could have unset it with SetCooperativeLevel, but not called
1836 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1837 * but we don't have any hwnd
1840 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1841 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1842 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1843 devmode.dmPelsWidth = pMode->Width;
1844 devmode.dmPelsHeight = pMode->Height;
1846 devmode.dmDisplayFrequency = pMode->RefreshRate;
1847 if (pMode->RefreshRate != 0) {
1848 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1851 /* Only change the mode if necessary */
1852 if( (This->ddraw_width == pMode->Width) &&
1853 (This->ddraw_height == pMode->Height) &&
1854 (This->ddraw_format == pMode->Format) &&
1855 (pMode->RefreshRate == 0) ) {
1856 return WINED3D_OK;
1859 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1860 if (ret != DISP_CHANGE_SUCCESSFUL) {
1861 if(devmode.dmDisplayFrequency != 0) {
1862 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1863 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1864 devmode.dmDisplayFrequency = 0;
1865 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1867 if(ret != DISP_CHANGE_SUCCESSFUL) {
1868 return DDERR_INVALIDMODE;
1872 /* Store the new values */
1873 This->ddraw_width = pMode->Width;
1874 This->ddraw_height = pMode->Height;
1875 This->ddraw_format = pMode->Format;
1877 /* Only do this with a window of course */
1878 if(This->ddraw_window)
1879 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1881 /* And finally clip mouse to our screen */
1882 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1883 ClipCursor(&clip_rc);
1885 return WINED3D_OK;
1888 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1890 *ppD3D= This->wineD3D;
1891 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1892 IWineD3D_AddRef(*ppD3D);
1893 return WINED3D_OK;
1896 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1897 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1898 * into the video ram as possible and seeing how many fit
1899 * you can also get the correct initial value from nvidia and ATI's driver via X
1900 * texture memory is video memory + AGP memory
1901 *******************/
1902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1903 static BOOL showfixmes = TRUE;
1904 if (showfixmes) {
1905 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1906 (wined3d_settings.emulated_textureram/(1024*1024)),
1907 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1908 showfixmes = FALSE;
1910 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1911 (wined3d_settings.emulated_textureram/(1024*1024)),
1912 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1913 /* return simulated texture memory left */
1914 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1919 /*****
1920 * Get / Set FVF
1921 *****/
1922 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1925 /* Update the current state block */
1926 This->updateStateBlock->changed.fvf = TRUE;
1927 This->updateStateBlock->set.fvf = TRUE;
1929 if(This->updateStateBlock->fvf == fvf) {
1930 TRACE("Application is setting the old fvf over, nothing to do\n");
1931 return WINED3D_OK;
1934 This->updateStateBlock->fvf = fvf;
1935 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1937 return WINED3D_OK;
1941 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1943 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1944 *pfvf = This->stateBlock->fvf;
1945 return WINED3D_OK;
1948 /*****
1949 * Get / Set Stream Source
1950 *****/
1951 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1953 IWineD3DVertexBuffer *oldSrc;
1955 if (StreamNumber >= MAX_STREAMS) {
1956 WARN("Stream out of range %d\n", StreamNumber);
1957 return WINED3DERR_INVALIDCALL;
1960 oldSrc = This->stateBlock->streamSource[StreamNumber];
1961 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1963 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1964 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1966 if(oldSrc == pStreamData &&
1967 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1968 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1969 TRACE("Application is setting the old values over, nothing to do\n");
1970 return WINED3D_OK;
1973 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1974 if (pStreamData) {
1975 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1976 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1979 /* Handle recording of state blocks */
1980 if (This->isRecordingState) {
1981 TRACE("Recording... not performing anything\n");
1982 return WINED3D_OK;
1985 /* Need to do a getParent and pass the reffs up */
1986 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
1987 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
1988 so for now, just count internally */
1989 if (pStreamData != NULL) {
1990 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
1991 InterlockedIncrement(&vbImpl->bindCount);
1993 if (oldSrc != NULL) {
1994 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
1997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1999 return WINED3D_OK;
2002 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2005 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2006 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2008 if (StreamNumber >= MAX_STREAMS) {
2009 WARN("Stream out of range %d\n", StreamNumber);
2010 return WINED3DERR_INVALIDCALL;
2012 *pStream = This->stateBlock->streamSource[StreamNumber];
2013 *pStride = This->stateBlock->streamStride[StreamNumber];
2014 if (pOffset) {
2015 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2018 if (*pStream != NULL) {
2019 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2021 return WINED3D_OK;
2024 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2026 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2027 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2029 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2030 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2032 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2033 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2034 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2036 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2037 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2041 return WINED3D_OK;
2044 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2047 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2048 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2050 TRACE("(%p) : returning %d\n", This, *Divider);
2052 return WINED3D_OK;
2055 /*****
2056 * Get / Set & Multiply Transform
2057 *****/
2058 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2061 /* Most of this routine, comments included copied from ddraw tree initially: */
2062 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2064 /* Handle recording of state blocks */
2065 if (This->isRecordingState) {
2066 TRACE("Recording... not performing anything\n");
2067 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2068 This->updateStateBlock->set.transform[d3dts] = TRUE;
2069 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2070 return WINED3D_OK;
2074 * If the new matrix is the same as the current one,
2075 * we cut off any further processing. this seems to be a reasonable
2076 * optimization because as was noticed, some apps (warcraft3 for example)
2077 * tend towards setting the same matrix repeatedly for some reason.
2079 * From here on we assume that the new matrix is different, wherever it matters.
2081 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2082 TRACE("The app is setting the same matrix over again\n");
2083 return WINED3D_OK;
2084 } else {
2085 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2089 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2090 where ViewMat = Camera space, WorldMat = world space.
2092 In OpenGL, camera and world space is combined into GL_MODELVIEW
2093 matrix. The Projection matrix stay projection matrix.
2096 /* Capture the times we can just ignore the change for now */
2097 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2098 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2099 /* Handled by the state manager */
2102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2103 return WINED3D_OK;
2106 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2108 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2109 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2110 return WINED3D_OK;
2113 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2114 WINED3DMATRIX *mat = NULL;
2115 WINED3DMATRIX temp;
2117 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2118 * below means it will be recorded in a state block change, but it
2119 * works regardless where it is recorded.
2120 * If this is found to be wrong, change to StateBlock.
2122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2123 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2125 if (State < HIGHEST_TRANSFORMSTATE)
2127 mat = &This->updateStateBlock->transforms[State];
2128 } else {
2129 FIXME("Unhandled transform state!!\n");
2132 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2134 /* Apply change via set transform - will reapply to eg. lights this way */
2135 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2138 /*****
2139 * Get / Set Light
2140 *****/
2141 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2142 you can reference any indexes you want as long as that number max are enabled at any
2143 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2144 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2145 but when recording, just build a chain pretty much of commands to be replayed. */
2147 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2148 float rho;
2149 PLIGHTINFOEL *object = NULL;
2150 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2151 struct list *e;
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2156 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2157 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2158 if(object->OriginalIndex == Index) break;
2159 object = NULL;
2162 if(!object) {
2163 TRACE("Adding new light\n");
2164 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2165 if(!object) {
2166 ERR("Out of memory error when allocating a light\n");
2167 return E_OUTOFMEMORY;
2169 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2170 object->glIndex = -1;
2171 object->OriginalIndex = Index;
2172 object->changed = TRUE;
2175 /* Initialize the object */
2176 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,
2177 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2178 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2179 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2180 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2181 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2182 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2184 /* Save away the information */
2185 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2187 switch (pLight->Type) {
2188 case WINED3DLIGHT_POINT:
2189 /* Position */
2190 object->lightPosn[0] = pLight->Position.x;
2191 object->lightPosn[1] = pLight->Position.y;
2192 object->lightPosn[2] = pLight->Position.z;
2193 object->lightPosn[3] = 1.0f;
2194 object->cutoff = 180.0f;
2195 /* FIXME: Range */
2196 break;
2198 case WINED3DLIGHT_DIRECTIONAL:
2199 /* Direction */
2200 object->lightPosn[0] = -pLight->Direction.x;
2201 object->lightPosn[1] = -pLight->Direction.y;
2202 object->lightPosn[2] = -pLight->Direction.z;
2203 object->lightPosn[3] = 0.0;
2204 object->exponent = 0.0f;
2205 object->cutoff = 180.0f;
2206 break;
2208 case WINED3DLIGHT_SPOT:
2209 /* Position */
2210 object->lightPosn[0] = pLight->Position.x;
2211 object->lightPosn[1] = pLight->Position.y;
2212 object->lightPosn[2] = pLight->Position.z;
2213 object->lightPosn[3] = 1.0;
2215 /* Direction */
2216 object->lightDirn[0] = pLight->Direction.x;
2217 object->lightDirn[1] = pLight->Direction.y;
2218 object->lightDirn[2] = pLight->Direction.z;
2219 object->lightDirn[3] = 1.0;
2222 * opengl-ish and d3d-ish spot lights use too different models for the
2223 * light "intensity" as a function of the angle towards the main light direction,
2224 * so we only can approximate very roughly.
2225 * however spot lights are rather rarely used in games (if ever used at all).
2226 * furthermore if still used, probably nobody pays attention to such details.
2228 if (pLight->Falloff == 0) {
2229 rho = 6.28f;
2230 } else {
2231 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2233 if (rho < 0.0001) rho = 0.0001f;
2234 object->exponent = -0.3/log(cos(rho/2));
2235 if (object->exponent > 128.0) {
2236 object->exponent = 128.0;
2238 object->cutoff = pLight->Phi*90/M_PI;
2240 /* FIXME: Range */
2241 break;
2243 default:
2244 FIXME("Unrecognized light type %d\n", pLight->Type);
2247 /* Update the live definitions if the light is currently assigned a glIndex */
2248 if (object->glIndex != -1 && !This->isRecordingState) {
2249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2251 return WINED3D_OK;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2255 PLIGHTINFOEL *lightInfo = NULL;
2256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2257 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2258 struct list *e;
2259 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2261 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2262 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2263 if(lightInfo->OriginalIndex == Index) break;
2264 lightInfo = NULL;
2267 if (lightInfo == NULL) {
2268 TRACE("Light information requested but light not defined\n");
2269 return WINED3DERR_INVALIDCALL;
2272 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2273 return WINED3D_OK;
2276 /*****
2277 * Get / Set Light Enable
2278 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2279 *****/
2280 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2281 PLIGHTINFOEL *lightInfo = NULL;
2282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2283 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2284 struct list *e;
2285 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2287 /* Tests show true = 128...not clear why */
2288 Enable = Enable? 128: 0;
2290 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2291 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2292 if(lightInfo->OriginalIndex == Index) break;
2293 lightInfo = NULL;
2295 TRACE("Found light: %p\n", lightInfo);
2297 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2298 if (lightInfo == NULL) {
2300 TRACE("Light enabled requested but light not defined, so defining one!\n");
2301 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2303 /* Search for it again! Should be fairly quick as near head of list */
2304 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2305 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2306 if(lightInfo->OriginalIndex == Index) break;
2307 lightInfo = NULL;
2309 if (lightInfo == NULL) {
2310 FIXME("Adding default lights has failed dismally\n");
2311 return WINED3DERR_INVALIDCALL;
2315 lightInfo->enabledChanged = TRUE;
2316 if(!Enable) {
2317 if(lightInfo->glIndex != -1) {
2318 if(!This->isRecordingState) {
2319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2322 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2323 lightInfo->glIndex = -1;
2324 } else {
2325 TRACE("Light already disabled, nothing to do\n");
2327 } else {
2328 if (lightInfo->glIndex != -1) {
2329 /* nop */
2330 TRACE("Nothing to do as light was enabled\n");
2331 } else {
2332 int i;
2333 /* Find a free gl light */
2334 for(i = 0; i < This->maxConcurrentLights; i++) {
2335 if(This->stateBlock->activeLights[i] == NULL) {
2336 This->stateBlock->activeLights[i] = lightInfo;
2337 lightInfo->glIndex = i;
2338 break;
2341 if(lightInfo->glIndex == -1) {
2342 ERR("Too many concurrently active lights\n");
2343 return WINED3DERR_INVALIDCALL;
2346 /* i == lightInfo->glIndex */
2347 if(!This->isRecordingState) {
2348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2353 return WINED3D_OK;
2356 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2358 PLIGHTINFOEL *lightInfo = NULL;
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 struct list *e;
2361 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2362 TRACE("(%p) : for idx(%d)\n", This, Index);
2364 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2365 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2366 if(lightInfo->OriginalIndex == Index) break;
2367 lightInfo = NULL;
2370 if (lightInfo == NULL) {
2371 TRACE("Light enabled state requested but light not defined\n");
2372 return WINED3DERR_INVALIDCALL;
2374 /* true is 128 according to SetLightEnable */
2375 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2376 return WINED3D_OK;
2379 /*****
2380 * Get / Set Clip Planes
2381 *****/
2382 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2386 /* Validate Index */
2387 if (Index >= GL_LIMITS(clipplanes)) {
2388 TRACE("Application has requested clipplane this device doesn't support\n");
2389 return WINED3DERR_INVALIDCALL;
2392 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2393 This->updateStateBlock->set.clipplane[Index] = TRUE;
2394 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2395 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2396 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2397 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2399 /* Handle recording of state blocks */
2400 if (This->isRecordingState) {
2401 TRACE("Recording... not performing anything\n");
2402 return WINED3D_OK;
2405 /* Apply it */
2407 ENTER_GL();
2409 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2410 glMatrixMode(GL_MODELVIEW);
2411 glPushMatrix();
2412 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2414 TRACE("Clipplane [%f,%f,%f,%f]\n",
2415 This->updateStateBlock->clipplane[Index][0],
2416 This->updateStateBlock->clipplane[Index][1],
2417 This->updateStateBlock->clipplane[Index][2],
2418 This->updateStateBlock->clipplane[Index][3]);
2419 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2420 checkGLcall("glClipPlane");
2422 glPopMatrix();
2423 LEAVE_GL();
2425 return WINED3D_OK;
2428 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 TRACE("(%p) : for idx %d\n", This, Index);
2432 /* Validate Index */
2433 if (Index >= GL_LIMITS(clipplanes)) {
2434 TRACE("Application has requested clipplane this device doesn't support\n");
2435 return WINED3DERR_INVALIDCALL;
2438 pPlane[0] = This->stateBlock->clipplane[Index][0];
2439 pPlane[1] = This->stateBlock->clipplane[Index][1];
2440 pPlane[2] = This->stateBlock->clipplane[Index][2];
2441 pPlane[3] = This->stateBlock->clipplane[Index][3];
2442 return WINED3D_OK;
2445 /*****
2446 * Get / Set Clip Plane Status
2447 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2448 *****/
2449 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2451 FIXME("(%p) : stub\n", This);
2452 if (NULL == pClipStatus) {
2453 return WINED3DERR_INVALIDCALL;
2455 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2456 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2457 return WINED3D_OK;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2462 FIXME("(%p) : stub\n", This);
2463 if (NULL == pClipStatus) {
2464 return WINED3DERR_INVALIDCALL;
2466 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2467 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2468 return WINED3D_OK;
2471 /*****
2472 * Get / Set Material
2473 *****/
2474 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2477 This->updateStateBlock->changed.material = TRUE;
2478 This->updateStateBlock->set.material = TRUE;
2479 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2481 /* Handle recording of state blocks */
2482 if (This->isRecordingState) {
2483 TRACE("Recording... not performing anything\n");
2484 return WINED3D_OK;
2487 ENTER_GL();
2488 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2489 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2490 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2491 pMaterial->Ambient.b, pMaterial->Ambient.a);
2492 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2493 pMaterial->Specular.b, pMaterial->Specular.a);
2494 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2495 pMaterial->Emissive.b, pMaterial->Emissive.a);
2496 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2498 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2499 checkGLcall("glMaterialfv(GL_AMBIENT)");
2500 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2501 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2503 /* Only change material color if specular is enabled, otherwise it is set to black */
2504 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2505 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2506 checkGLcall("glMaterialfv(GL_SPECULAR");
2507 } else {
2508 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2509 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2510 checkGLcall("glMaterialfv(GL_SPECULAR");
2512 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2513 checkGLcall("glMaterialfv(GL_EMISSION)");
2514 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2515 checkGLcall("glMaterialf(GL_SHININESS");
2517 LEAVE_GL();
2518 return WINED3D_OK;
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2524 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2525 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2526 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2527 pMaterial->Ambient.b, pMaterial->Ambient.a);
2528 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2529 pMaterial->Specular.b, pMaterial->Specular.a);
2530 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2531 pMaterial->Emissive.b, pMaterial->Emissive.a);
2532 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2534 return WINED3D_OK;
2537 /*****
2538 * Get / Set Indices
2539 *****/
2540 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2541 UINT BaseVertexIndex) {
2542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2543 IWineD3DIndexBuffer *oldIdxs;
2544 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2546 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2547 oldIdxs = This->updateStateBlock->pIndexData;
2549 This->updateStateBlock->changed.indices = TRUE;
2550 This->updateStateBlock->set.indices = TRUE;
2551 This->updateStateBlock->pIndexData = pIndexData;
2552 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2554 /* Handle recording of state blocks */
2555 if (This->isRecordingState) {
2556 TRACE("Recording... not performing anything\n");
2557 return WINED3D_OK;
2560 /* So far only the base vertex index is tracked */
2561 if(BaseVertexIndex != oldBaseIndex) {
2562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2564 return WINED3D_OK;
2567 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 *ppIndexData = This->stateBlock->pIndexData;
2572 /* up ref count on ppindexdata */
2573 if (*ppIndexData) {
2574 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2575 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2576 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2577 }else{
2578 TRACE("(%p) No index data set\n", This);
2580 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2582 return WINED3D_OK;
2585 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2586 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 TRACE("(%p)->(%d)\n", This, BaseIndex);
2590 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2591 TRACE("Application is setting the old value over, nothing to do\n");
2592 return WINED3D_OK;
2595 This->updateStateBlock->baseVertexIndex = BaseIndex;
2597 if (This->isRecordingState) {
2598 TRACE("Recording... not performing anything\n");
2599 return WINED3D_OK;
2601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2602 return WINED3D_OK;
2605 /*****
2606 * Get / Set Viewports
2607 *****/
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 TRACE("(%p)\n", This);
2612 This->updateStateBlock->changed.viewport = TRUE;
2613 This->updateStateBlock->set.viewport = TRUE;
2614 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2616 /* Handle recording of state blocks */
2617 if (This->isRecordingState) {
2618 TRACE("Recording... not performing anything\n");
2619 return WINED3D_OK;
2622 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2623 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2626 return WINED3D_OK;
2630 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p)\n", This);
2633 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2634 return WINED3D_OK;
2637 /*****
2638 * Get / Set Render States
2639 * TODO: Verify against dx9 definitions
2640 *****/
2641 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2644 DWORD oldValue = This->stateBlock->renderState[State];
2646 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2648 This->updateStateBlock->changed.renderState[State] = TRUE;
2649 This->updateStateBlock->set.renderState[State] = TRUE;
2650 This->updateStateBlock->renderState[State] = Value;
2652 /* Handle recording of state blocks */
2653 if (This->isRecordingState) {
2654 TRACE("Recording... not performing anything\n");
2655 return WINED3D_OK;
2658 /* Compared here and not before the assignment to allow proper stateblock recording */
2659 if(Value == oldValue) {
2660 TRACE("Application is setting the old value over, nothing to do\n");
2661 } else {
2662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2665 return WINED3D_OK;
2668 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2671 *pValue = This->stateBlock->renderState[State];
2672 return WINED3D_OK;
2675 /*****
2676 * Get / Set Sampler States
2677 * TODO: Verify against dx9 definitions
2678 *****/
2680 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2682 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2685 * SetSampler is designed to allow for more than the standard up to 8 textures
2686 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2687 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2689 * http://developer.nvidia.com/object/General_FAQ.html#t6
2691 * There are two new settings for GForce
2692 * the sampler one:
2693 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2694 * and the texture one:
2695 * GL_MAX_TEXTURE_COORDS_ARB.
2696 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2697 ******************/
2698 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2699 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
2700 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2701 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
2702 return WINED3DERR_INVALIDCALL;
2705 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2706 debug_d3dsamplerstate(Type), Type, Value);
2707 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2708 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2709 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2711 /* Handle recording of state blocks */
2712 if (This->isRecordingState) {
2713 TRACE("Recording... not performing anything\n");
2714 return WINED3D_OK;
2717 if(oldValue == Value) {
2718 TRACE("Application is setting the old value over, nothing to do\n");
2719 return WINED3D_OK;
2722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2724 return WINED3D_OK;
2727 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2729 /** TODO: check that sampler is in range **/
2730 *Value = This->stateBlock->samplerState[Sampler][Type];
2731 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2733 return WINED3D_OK;
2736 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2738 RECT windowRect;
2739 UINT winHeight;
2741 This->updateStateBlock->set.scissorRect = TRUE;
2742 This->updateStateBlock->changed.scissorRect = TRUE;
2743 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2745 if(This->isRecordingState) {
2746 TRACE("Recording... not performing anything\n");
2747 return WINED3D_OK;
2750 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
2751 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2752 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2754 winHeight = windowRect.bottom - windowRect.top;
2755 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
2756 pRect->right - pRect->left, pRect->bottom - pRect->top);
2757 ENTER_GL();
2758 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
2759 checkGLcall("glScissor");
2760 LEAVE_GL();
2762 return WINED3D_OK;
2765 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2769 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2770 return WINED3D_OK;
2773 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2775 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2777 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2779 This->updateStateBlock->vertexDecl = pDecl;
2780 This->updateStateBlock->changed.vertexDecl = TRUE;
2781 This->updateStateBlock->set.vertexDecl = TRUE;
2783 if (This->isRecordingState) {
2784 TRACE("Recording... not performing anything\n");
2785 return WINED3D_OK;
2786 } else if(pDecl == oldDecl) {
2787 /* Checked after the assignment to allow proper stateblock recording */
2788 TRACE("Application is setting the old declaration over, nothing to do\n");
2789 return WINED3D_OK;
2792 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2793 return WINED3D_OK;
2796 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2801 *ppDecl = This->stateBlock->vertexDecl;
2802 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2803 return WINED3D_OK;
2806 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2810 This->updateStateBlock->vertexShader = pShader;
2811 This->updateStateBlock->changed.vertexShader = TRUE;
2812 This->updateStateBlock->set.vertexShader = TRUE;
2814 if (This->isRecordingState) {
2815 TRACE("Recording... not performing anything\n");
2816 return WINED3D_OK;
2817 } else if(oldShader == pShader) {
2818 /* Checked here to allow proper stateblock recording */
2819 TRACE("App is setting the old shader over, nothing to do\n");
2820 return WINED3D_OK;
2823 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2827 return WINED3D_OK;
2830 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 if (NULL == ppShader) {
2834 return WINED3DERR_INVALIDCALL;
2836 *ppShader = This->stateBlock->vertexShader;
2837 if( NULL != *ppShader)
2838 IWineD3DVertexShader_AddRef(*ppShader);
2840 TRACE("(%p) : returning %p\n", This, *ppShader);
2841 return WINED3D_OK;
2844 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2845 IWineD3DDevice *iface,
2846 UINT start,
2847 CONST BOOL *srcData,
2848 UINT count) {
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 int i, cnt = min(count, MAX_CONST_B - start);
2853 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2854 iface, srcData, start, count);
2856 if (srcData == NULL || cnt < 0)
2857 return WINED3DERR_INVALIDCALL;
2859 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2860 for (i = 0; i < cnt; i++)
2861 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2863 for (i = start; i < cnt + start; ++i) {
2864 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2865 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2870 return WINED3D_OK;
2873 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2874 IWineD3DDevice *iface,
2875 UINT start,
2876 BOOL *dstData,
2877 UINT count) {
2879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2880 int cnt = min(count, MAX_CONST_B - start);
2882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2883 iface, dstData, start, count);
2885 if (dstData == NULL || cnt < 0)
2886 return WINED3DERR_INVALIDCALL;
2888 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2889 return WINED3D_OK;
2892 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2893 IWineD3DDevice *iface,
2894 UINT start,
2895 CONST int *srcData,
2896 UINT count) {
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2899 int i, cnt = min(count, MAX_CONST_I - start);
2901 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2902 iface, srcData, start, count);
2904 if (srcData == NULL || cnt < 0)
2905 return WINED3DERR_INVALIDCALL;
2907 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2908 for (i = 0; i < cnt; i++)
2909 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2910 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2912 for (i = start; i < cnt + start; ++i) {
2913 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2914 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2919 return WINED3D_OK;
2922 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2923 IWineD3DDevice *iface,
2924 UINT start,
2925 int *dstData,
2926 UINT count) {
2928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2929 int cnt = min(count, MAX_CONST_I - start);
2931 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2932 iface, dstData, start, count);
2934 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2935 return WINED3DERR_INVALIDCALL;
2937 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2938 return WINED3D_OK;
2941 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2942 IWineD3DDevice *iface,
2943 UINT start,
2944 CONST float *srcData,
2945 UINT count) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2948 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2950 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2951 iface, srcData, start, count);
2953 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
2954 return WINED3DERR_INVALIDCALL;
2956 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
2957 for (i = 0; i < cnt; i++)
2958 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2959 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2961 for (i = start; i < cnt + start; ++i) {
2962 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
2963 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
2964 ptr->idx = i;
2965 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
2966 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
2968 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2973 return WINED3D_OK;
2976 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2977 IWineD3DDevice *iface,
2978 UINT start,
2979 float *dstData,
2980 UINT count) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2985 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2986 iface, dstData, start, count);
2988 if (dstData == NULL || cnt < 0)
2989 return WINED3DERR_INVALIDCALL;
2991 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2992 return WINED3D_OK;
2995 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2996 DWORD i;
2997 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
2998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3002 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3003 DWORD i, tex;
3004 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3005 * it is never called.
3007 * Rules are:
3008 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3009 * that would be really messy and require shader recompilation
3010 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3011 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3012 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3013 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3015 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3016 if(This->oneToOneTexUnitMap) {
3017 TRACE("Not touching 1:1 map\n");
3018 return;
3020 TRACE("Restoring 1:1 texture unit mapping\n");
3021 /* Restore a 1:1 mapping */
3022 for(i = 0; i < MAX_SAMPLERS; i++) {
3023 if(This->texUnitMap[i] != i) {
3024 This->texUnitMap[i] = i;
3025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3026 markTextureStagesDirty(This, i);
3029 This->oneToOneTexUnitMap = TRUE;
3030 return;
3031 } else {
3032 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3033 * First, see if we can succeed at all
3035 tex = 0;
3036 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3037 if(This->stateBlock->textures[i] == NULL) tex++;
3040 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3041 FIXME("Too many bound textures to support the combiner settings\n");
3042 return;
3045 /* Now work out the mapping */
3046 tex = 0;
3047 This->oneToOneTexUnitMap = FALSE;
3048 WARN("Non 1:1 mapping UNTESTED!\n");
3049 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3050 /* Skip NULL textures */
3051 if (!This->stateBlock->textures[i]) {
3052 /* Map to -1, so the check below doesn't fail if a non-NULL
3053 * texture is set on this stage */
3054 TRACE("Mapping texture stage %d to -1\n", i);
3055 This->texUnitMap[i] = -1;
3057 continue;
3060 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3061 if(This->texUnitMap[i] != tex) {
3062 This->texUnitMap[i] = tex;
3063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3064 markTextureStagesDirty(This, i);
3067 ++tex;
3072 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3075 This->updateStateBlock->pixelShader = pShader;
3076 This->updateStateBlock->changed.pixelShader = TRUE;
3077 This->updateStateBlock->set.pixelShader = TRUE;
3079 /* Handle recording of state blocks */
3080 if (This->isRecordingState) {
3081 TRACE("Recording... not performing anything\n");
3084 if (This->isRecordingState) {
3085 TRACE("Recording... not performing anything\n");
3086 return WINED3D_OK;
3089 if(pShader == oldShader) {
3090 TRACE("App is setting the old pixel shader over, nothing to do\n");
3091 return WINED3D_OK;
3094 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3097 /* Rebuild the texture unit mapping if nvrc's are supported */
3098 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3099 IWineD3DDeviceImpl_FindTexUnitMap(This);
3102 return WINED3D_OK;
3105 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 if (NULL == ppShader) {
3109 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3110 return WINED3DERR_INVALIDCALL;
3113 *ppShader = This->stateBlock->pixelShader;
3114 if (NULL != *ppShader) {
3115 IWineD3DPixelShader_AddRef(*ppShader);
3117 TRACE("(%p) : returning %p\n", This, *ppShader);
3118 return WINED3D_OK;
3121 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3122 IWineD3DDevice *iface,
3123 UINT start,
3124 CONST BOOL *srcData,
3125 UINT count) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 int i, cnt = min(count, MAX_CONST_B - start);
3130 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3131 iface, srcData, start, count);
3133 if (srcData == NULL || cnt < 0)
3134 return WINED3DERR_INVALIDCALL;
3136 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3137 for (i = 0; i < cnt; i++)
3138 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3140 for (i = start; i < cnt + start; ++i) {
3141 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3142 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3147 return WINED3D_OK;
3150 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3151 IWineD3DDevice *iface,
3152 UINT start,
3153 BOOL *dstData,
3154 UINT count) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 int cnt = min(count, MAX_CONST_B - start);
3159 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3160 iface, dstData, start, count);
3162 if (dstData == NULL || cnt < 0)
3163 return WINED3DERR_INVALIDCALL;
3165 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3166 return WINED3D_OK;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3170 IWineD3DDevice *iface,
3171 UINT start,
3172 CONST int *srcData,
3173 UINT count) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3176 int i, cnt = min(count, MAX_CONST_I - start);
3178 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3179 iface, srcData, start, count);
3181 if (srcData == NULL || cnt < 0)
3182 return WINED3DERR_INVALIDCALL;
3184 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3185 for (i = 0; i < cnt; i++)
3186 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3187 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3189 for (i = start; i < cnt + start; ++i) {
3190 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3191 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3196 return WINED3D_OK;
3199 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3200 IWineD3DDevice *iface,
3201 UINT start,
3202 int *dstData,
3203 UINT count) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 int cnt = min(count, MAX_CONST_I - start);
3208 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3209 iface, dstData, start, count);
3211 if (dstData == NULL || cnt < 0)
3212 return WINED3DERR_INVALIDCALL;
3214 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3215 return WINED3D_OK;
3218 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3219 IWineD3DDevice *iface,
3220 UINT start,
3221 CONST float *srcData,
3222 UINT count) {
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3227 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3228 iface, srcData, start, count);
3230 if (srcData == NULL || cnt < 0)
3231 return WINED3DERR_INVALIDCALL;
3233 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3234 for (i = 0; i < cnt; i++)
3235 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3236 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3238 for (i = start; i < cnt + start; ++i) {
3239 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3240 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3241 ptr->idx = i;
3242 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3243 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3245 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3250 return WINED3D_OK;
3253 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3254 IWineD3DDevice *iface,
3255 UINT start,
3256 float *dstData,
3257 UINT count) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3260 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3262 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3263 iface, dstData, start, count);
3265 if (dstData == NULL || cnt < 0)
3266 return WINED3DERR_INVALIDCALL;
3268 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3269 return WINED3D_OK;
3272 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3273 static HRESULT
3274 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3275 char *dest_ptr, *dest_conv = NULL;
3276 unsigned int i;
3277 DWORD DestFVF = dest->fvf;
3278 WINED3DVIEWPORT vp;
3279 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3280 BOOL doClip;
3281 int numTextures;
3283 if (SrcFVF & WINED3DFVF_NORMAL) {
3284 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3287 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3288 ERR("Source has no position mask\n");
3289 return WINED3DERR_INVALIDCALL;
3292 /* We might access VBOs from this code, so hold the lock */
3293 ENTER_GL();
3295 if (dest->resource.allocatedMemory == NULL) {
3296 /* This may happen if we do direct locking into a vbo. Unlikely,
3297 * but theoretically possible(ddraw processvertices test)
3299 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3300 if(!dest->resource.allocatedMemory) {
3301 LEAVE_GL();
3302 ERR("Out of memory\n");
3303 return E_OUTOFMEMORY;
3305 if(dest->vbo) {
3306 void *src;
3307 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3308 checkGLcall("glBindBufferARB");
3309 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3310 if(src) {
3311 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3313 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3314 checkGLcall("glUnmapBufferARB");
3318 /* Get a pointer into the destination vbo(create one if none exists) and
3319 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3321 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3322 CreateVBO(dest);
3325 if(dest->vbo) {
3326 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3327 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3328 if(!dest_conv) {
3329 ERR("glMapBuffer failed\n");
3330 /* Continue without storing converted vertices */
3334 /* Should I clip?
3335 * a) WINED3DRS_CLIPPING is enabled
3336 * b) WINED3DVOP_CLIP is passed
3338 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3339 static BOOL warned = FALSE;
3341 * The clipping code is not quite correct. Some things need
3342 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3343 * so disable clipping for now.
3344 * (The graphics in Half-Life are broken, and my processvertices
3345 * test crashes with IDirect3DDevice3)
3346 doClip = TRUE;
3348 doClip = FALSE;
3349 if(!warned) {
3350 warned = TRUE;
3351 FIXME("Clipping is broken and disabled for now\n");
3353 } else doClip = FALSE;
3354 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3355 if(dest_conv) {
3356 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3359 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3360 WINED3DTS_VIEW,
3361 &view_mat);
3362 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3363 WINED3DTS_PROJECTION,
3364 &proj_mat);
3365 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3366 WINED3DTS_WORLDMATRIX(0),
3367 &world_mat);
3369 TRACE("View mat:\n");
3370 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);
3371 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);
3372 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);
3373 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);
3375 TRACE("Proj mat:\n");
3376 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);
3377 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);
3378 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);
3379 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);
3381 TRACE("World mat:\n");
3382 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);
3383 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);
3384 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);
3385 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);
3387 /* Get the viewport */
3388 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3389 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3390 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3392 multiply_matrix(&mat,&view_mat,&world_mat);
3393 multiply_matrix(&mat,&proj_mat,&mat);
3395 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3397 for (i = 0; i < dwCount; i+= 1) {
3398 unsigned int tex_index;
3400 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3401 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3402 /* The position first */
3403 float *p =
3404 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3405 float x, y, z, rhw;
3406 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3408 /* Multiplication with world, view and projection matrix */
3409 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);
3410 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);
3411 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);
3412 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);
3414 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3416 /* WARNING: The following things are taken from d3d7 and were not yet checked
3417 * against d3d8 or d3d9!
3420 /* Clipping conditions: From
3421 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3423 * A vertex is clipped if it does not match the following requirements
3424 * -rhw < x <= rhw
3425 * -rhw < y <= rhw
3426 * 0 < z <= rhw
3427 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3429 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3430 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3434 if( !doClip ||
3435 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3436 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3437 ( rhw > eps ) ) ) {
3439 /* "Normal" viewport transformation (not clipped)
3440 * 1) The values are divided by rhw
3441 * 2) The y axis is negative, so multiply it with -1
3442 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3443 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3444 * 4) Multiply x with Width/2 and add Width/2
3445 * 5) The same for the height
3446 * 6) Add the viewpoint X and Y to the 2D coordinates and
3447 * The minimum Z value to z
3448 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3450 * Well, basically it's simply a linear transformation into viewport
3451 * coordinates
3454 x /= rhw;
3455 y /= rhw;
3456 z /= rhw;
3458 y *= -1;
3460 x *= vp.Width / 2;
3461 y *= vp.Height / 2;
3462 z *= vp.MaxZ - vp.MinZ;
3464 x += vp.Width / 2 + vp.X;
3465 y += vp.Height / 2 + vp.Y;
3466 z += vp.MinZ;
3468 rhw = 1 / rhw;
3469 } else {
3470 /* That vertex got clipped
3471 * Contrary to OpenGL it is not dropped completely, it just
3472 * undergoes a different calculation.
3474 TRACE("Vertex got clipped\n");
3475 x += rhw;
3476 y += rhw;
3478 x /= 2;
3479 y /= 2;
3481 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3482 * outside of the main vertex buffer memory. That needs some more
3483 * investigation...
3487 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3490 ( (float *) dest_ptr)[0] = x;
3491 ( (float *) dest_ptr)[1] = y;
3492 ( (float *) dest_ptr)[2] = z;
3493 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3495 dest_ptr += 3 * sizeof(float);
3497 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3498 dest_ptr += sizeof(float);
3501 if(dest_conv) {
3502 float w = 1 / rhw;
3503 ( (float *) dest_conv)[0] = x * w;
3504 ( (float *) dest_conv)[1] = y * w;
3505 ( (float *) dest_conv)[2] = z * w;
3506 ( (float *) dest_conv)[3] = w;
3508 dest_conv += 3 * sizeof(float);
3510 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3511 dest_conv += sizeof(float);
3515 if (DestFVF & WINED3DFVF_PSIZE) {
3516 dest_ptr += sizeof(DWORD);
3517 if(dest_conv) dest_conv += sizeof(DWORD);
3519 if (DestFVF & WINED3DFVF_NORMAL) {
3520 float *normal =
3521 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3522 /* AFAIK this should go into the lighting information */
3523 FIXME("Didn't expect the destination to have a normal\n");
3524 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3525 if(dest_conv) {
3526 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3530 if (DestFVF & WINED3DFVF_DIFFUSE) {
3531 DWORD *color_d =
3532 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3533 if(!color_d) {
3534 static BOOL warned = FALSE;
3536 if(!warned) {
3537 ERR("No diffuse color in source, but destination has one\n");
3538 warned = TRUE;
3541 *( (DWORD *) dest_ptr) = 0xffffffff;
3542 dest_ptr += sizeof(DWORD);
3544 if(dest_conv) {
3545 *( (DWORD *) dest_conv) = 0xffffffff;
3546 dest_conv += sizeof(DWORD);
3549 else {
3550 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3551 if(dest_conv) {
3552 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3553 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3554 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3555 dest_conv += sizeof(DWORD);
3560 if (DestFVF & WINED3DFVF_SPECULAR) {
3561 /* What's the color value in the feedback buffer? */
3562 DWORD *color_s =
3563 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3564 if(!color_s) {
3565 static BOOL warned = FALSE;
3567 if(!warned) {
3568 ERR("No specular color in source, but destination has one\n");
3569 warned = TRUE;
3572 *( (DWORD *) dest_ptr) = 0xFF000000;
3573 dest_ptr += sizeof(DWORD);
3575 if(dest_conv) {
3576 *( (DWORD *) dest_conv) = 0xFF000000;
3577 dest_conv += sizeof(DWORD);
3580 else {
3581 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3582 if(dest_conv) {
3583 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3584 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3585 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3586 dest_conv += sizeof(DWORD);
3591 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3592 float *tex_coord =
3593 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3594 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3595 if(!tex_coord) {
3596 ERR("No source texture, but destination requests one\n");
3597 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3598 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3600 else {
3601 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3602 if(dest_conv) {
3603 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3609 if(dest_conv) {
3610 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3611 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3614 LEAVE_GL();
3616 return WINED3D_OK;
3618 #undef copy_and_next
3620 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3622 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3623 WineDirect3DVertexStridedData strided;
3624 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3626 if (!SrcImpl) {
3627 WARN("NULL source vertex buffer\n");
3628 return WINED3DERR_INVALIDCALL;
3630 /* We don't need the source vbo because this buffer is only used as
3631 * a source for ProcessVertices. Avoid wasting resources by converting the
3632 * buffer and loading the VBO
3634 if(SrcImpl->vbo) {
3635 TRACE("Releasing the source vbo, it won't be needed\n");
3637 if(!SrcImpl->resource.allocatedMemory) {
3638 /* Rescue the data from the buffer */
3639 void *src;
3640 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3641 if(!SrcImpl->resource.allocatedMemory) {
3642 ERR("Out of memory\n");
3643 return E_OUTOFMEMORY;
3646 ENTER_GL();
3647 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3648 checkGLcall("glBindBufferARB");
3650 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3651 if(src) {
3652 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3655 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3656 checkGLcall("glUnmapBufferARB");
3657 } else {
3658 ENTER_GL();
3661 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3662 checkGLcall("glBindBufferARB");
3663 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3664 checkGLcall("glDeleteBuffersARB");
3665 LEAVE_GL();
3667 SrcImpl->vbo = 0;
3670 memset(&strided, 0, sizeof(strided));
3671 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3673 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3676 /*****
3677 * Get / Set Texture Stage States
3678 * TODO: Verify against dx9 definitions
3679 *****/
3680 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3682 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3684 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3686 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3688 /* Reject invalid texture units */
3689 if (Stage >= GL_LIMITS(texture_stages)) {
3690 TRACE("Attempt to access invalid texture rejected\n");
3691 return WINED3DERR_INVALIDCALL;
3694 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3695 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3696 This->updateStateBlock->textureState[Stage][Type] = Value;
3698 if (This->isRecordingState) {
3699 TRACE("Recording... not performing anything\n");
3700 return WINED3D_OK;
3703 /* Checked after the assignments to allow proper stateblock recording */
3704 if(oldValue == Value) {
3705 TRACE("App is setting the old value over, nothing to do\n");
3706 return WINED3D_OK;
3709 if(Stage > This->stateBlock->lowest_disabled_stage &&
3710 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3711 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3712 * Changes in other states are important on disabled stages too
3714 return WINED3D_OK;
3717 if(Type == WINED3DTSS_COLOROP) {
3718 int i;
3720 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3721 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3722 * they have to be disabled
3724 * The current stage is dirtified below.
3726 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3727 TRACE("Additionally dirtifying stage %d\n", i);
3728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3730 This->stateBlock->lowest_disabled_stage = Stage;
3731 TRACE("New lowest disabled: %d\n", Stage);
3732 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3733 /* Previously disabled stage enabled. Stages above it may need enabling
3734 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3735 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3737 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3740 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3741 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3742 break;
3744 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3747 This->stateBlock->lowest_disabled_stage = i;
3748 TRACE("New lowest disabled: %d\n", i);
3750 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3751 /* TODO: Built a stage -> texture unit mapping for register combiners */
3755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3757 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3758 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3759 * will call FindTexUnitMap too.
3761 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3762 IWineD3DDeviceImpl_FindTexUnitMap(This);
3764 return WINED3D_OK;
3767 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3769 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3770 *pValue = This->updateStateBlock->textureState[Stage][Type];
3771 return WINED3D_OK;
3774 /*****
3775 * Get / Set Texture
3776 *****/
3777 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 IWineD3DBaseTexture *oldTexture;
3782 oldTexture = This->updateStateBlock->textures[Stage];
3783 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3785 #if 0 /* TODO: check so vertex textures */
3786 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3787 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3788 return WINED3D_OK;
3790 #endif
3792 /* Reject invalid texture units */
3793 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
3794 WARN("Attempt to access invalid texture rejected\n");
3795 return WINED3DERR_INVALIDCALL;
3798 if(pTexture != NULL) {
3799 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3801 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3802 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3803 return WINED3DERR_INVALIDCALL;
3805 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3808 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3809 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3811 This->updateStateBlock->set.textures[Stage] = TRUE;
3812 This->updateStateBlock->changed.textures[Stage] = TRUE;
3813 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3814 This->updateStateBlock->textures[Stage] = pTexture;
3816 /* Handle recording of state blocks */
3817 if (This->isRecordingState) {
3818 TRACE("Recording... not performing anything\n");
3819 return WINED3D_OK;
3822 if(oldTexture == pTexture) {
3823 TRACE("App is setting the same texture again, nothing to do\n");
3824 return WINED3D_OK;
3827 /** NOTE: MSDN says that setTexture increases the reference count,
3828 * and the the application nust set the texture back to null (or have a leaky application),
3829 * This means we should pass the refcount up to the parent
3830 *******************************/
3831 if (NULL != This->updateStateBlock->textures[Stage]) {
3832 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3833 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3835 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3836 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3837 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3838 * so the COLOROP and ALPHAOP have to be dirtified.
3840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3843 if(bindCount == 1) {
3844 new->baseTexture.sampler = Stage;
3846 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3850 if (NULL != oldTexture) {
3851 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3852 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3854 IWineD3DBaseTexture_Release(oldTexture);
3855 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3860 if(bindCount && old->baseTexture.sampler == Stage) {
3861 int i;
3862 /* Have to do a search for the other sampler(s) where the texture is bound to
3863 * Shouldn't happen as long as apps bind a texture only to one stage
3865 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3866 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3867 if(This->updateStateBlock->textures[i] == oldTexture) {
3868 old->baseTexture.sampler = i;
3869 break;
3875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3877 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3878 * pixel shader is used
3880 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3881 IWineD3DDeviceImpl_FindTexUnitMap(This);
3884 return WINED3D_OK;
3887 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3889 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3891 /* Reject invalid texture units */
3892 if (Stage >= GL_LIMITS(sampler_stages)) {
3893 TRACE("Attempt to access invalid texture rejected\n");
3894 return WINED3DERR_INVALIDCALL;
3896 *ppTexture=This->stateBlock->textures[Stage];
3897 if (*ppTexture)
3898 IWineD3DBaseTexture_AddRef(*ppTexture);
3900 return WINED3D_OK;
3903 /*****
3904 * Get Back Buffer
3905 *****/
3906 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3907 IWineD3DSurface **ppBackBuffer) {
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 IWineD3DSwapChain *swapChain;
3910 HRESULT hr;
3912 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3914 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3915 if (hr == WINED3D_OK) {
3916 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3917 IWineD3DSwapChain_Release(swapChain);
3918 } else {
3919 *ppBackBuffer = NULL;
3921 return hr;
3924 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3926 WARN("(%p) : stub, calling idirect3d for now\n", This);
3927 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3930 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3932 IWineD3DSwapChain *swapChain;
3933 HRESULT hr;
3935 if(iSwapChain > 0) {
3936 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3937 if (hr == WINED3D_OK) {
3938 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3939 IWineD3DSwapChain_Release(swapChain);
3940 } else {
3941 FIXME("(%p) Error getting display mode\n", This);
3943 } else {
3944 /* Don't read the real display mode,
3945 but return the stored mode instead. X11 can't change the color
3946 depth, and some apps are pretty angry if they SetDisplayMode from
3947 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3949 Also don't relay to the swapchain because with ddraw it's possible
3950 that there isn't a swapchain at all */
3951 pMode->Width = This->ddraw_width;
3952 pMode->Height = This->ddraw_height;
3953 pMode->Format = This->ddraw_format;
3954 pMode->RefreshRate = 0;
3955 hr = WINED3D_OK;
3958 return hr;
3961 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
3962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3963 TRACE("(%p)->(%p)\n", This, hWnd);
3965 if(This->ddraw_fullscreen) {
3966 if(This->ddraw_window && This->ddraw_window != hWnd) {
3967 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
3969 if(hWnd && This->ddraw_window != hWnd) {
3970 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
3974 This->ddraw_window = hWnd;
3975 return WINED3D_OK;
3978 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
3979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3980 TRACE("(%p)->(%p)\n", This, hWnd);
3982 *hWnd = This->ddraw_window;
3983 return WINED3D_OK;
3986 /*****
3987 * Stateblock related functions
3988 *****/
3990 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 IWineD3DStateBlockImpl *object;
3993 HRESULT temp_result;
3994 int i;
3996 TRACE("(%p)\n", This);
3998 if (This->isRecordingState) {
3999 return WINED3DERR_INVALIDCALL;
4002 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4003 if (NULL == object ) {
4004 FIXME("(%p)Error allocating memory for stateblock\n", This);
4005 return E_OUTOFMEMORY;
4007 TRACE("(%p) created object %p\n", This, object);
4008 object->wineD3DDevice= This;
4009 /** FIXME: object->parent = parent; **/
4010 object->parent = NULL;
4011 object->blockType = WINED3DSBT_ALL;
4012 object->ref = 1;
4013 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4015 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4016 list_init(&object->lightMap[i]);
4019 temp_result = allocate_shader_constants(object);
4020 if (WINED3D_OK != temp_result)
4021 return temp_result;
4023 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4024 This->updateStateBlock = object;
4025 This->isRecordingState = TRUE;
4027 TRACE("(%p) recording stateblock %p\n",This , object);
4028 return WINED3D_OK;
4031 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4034 if (!This->isRecordingState) {
4035 FIXME("(%p) not recording! returning error\n", This);
4036 *ppStateBlock = NULL;
4037 return WINED3DERR_INVALIDCALL;
4040 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4041 This->isRecordingState = FALSE;
4042 This->updateStateBlock = This->stateBlock;
4043 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4044 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4045 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4046 return WINED3D_OK;
4049 /*****
4050 * Scene related functions
4051 *****/
4052 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4053 /* At the moment we have no need for any functionality at the beginning
4054 of a scene */
4055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4056 TRACE("(%p)\n", This);
4058 if(This->inScene) {
4059 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4060 return WINED3DERR_INVALIDCALL;
4062 This->inScene = TRUE;
4063 return WINED3D_OK;
4066 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4068 TRACE("(%p)\n", This);
4070 if(!This->inScene) {
4071 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4072 return WINED3DERR_INVALIDCALL;
4075 ENTER_GL();
4076 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4077 glFlush();
4078 checkGLcall("glFlush");
4079 LEAVE_GL();
4081 This->inScene = FALSE;
4082 return WINED3D_OK;
4085 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4086 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4087 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4089 IWineD3DSwapChain *swapChain = NULL;
4090 int i;
4091 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4093 TRACE("(%p) Presenting the frame\n", This);
4095 for(i = 0 ; i < swapchains ; i ++) {
4097 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4098 TRACE("presentinng chain %d, %p\n", i, swapChain);
4099 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4100 IWineD3DSwapChain_Release(swapChain);
4103 return WINED3D_OK;
4106 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4107 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4110 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4111 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4112 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4113 GLbitfield glMask = 0;
4114 GLboolean old_ztest;
4115 GLfloat old_z_clear_value;
4116 GLint old_stencil_clear_value;
4117 GLfloat old_color_clear_value[4];
4118 unsigned int i;
4119 CONST WINED3DRECT* curRect;
4121 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4122 Count, pRects, Flags, Z, Stencil);
4124 ENTER_GL();
4126 glEnable(GL_SCISSOR_TEST);
4127 checkGLcall("glEnable GL_SCISSOR_TEST");
4129 if (Count > 0 && pRects) {
4130 curRect = pRects;
4131 } else {
4132 curRect = NULL;
4135 /* Only set the values up once, as they are not changing */
4136 if (Flags & WINED3DCLEAR_STENCIL) {
4137 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4138 glClearStencil(Stencil);
4139 checkGLcall("glClearStencil");
4140 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4141 glStencilMask(0xFFFFFFFF);
4144 if (Flags & WINED3DCLEAR_ZBUFFER) {
4145 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4146 glDepthMask(GL_TRUE);
4147 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4148 glClearDepth(Z);
4149 checkGLcall("glClearDepth");
4150 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4153 if (Flags & WINED3DCLEAR_TARGET) {
4154 TRACE("Clearing screen with glClear to color %x\n", Color);
4155 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4156 glClearColor(D3DCOLOR_R(Color),
4157 D3DCOLOR_G(Color),
4158 D3DCOLOR_B(Color),
4159 D3DCOLOR_A(Color));
4160 checkGLcall("glClearColor");
4162 /* Clear ALL colors! */
4163 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4164 glMask = glMask | GL_COLOR_BUFFER_BIT;
4167 /* Now process each rect in turn */
4168 for (i = 0; i < Count || i == 0; i++) {
4170 if (curRect) {
4171 /* Note gl uses lower left, width/height */
4172 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4173 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4174 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4175 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4176 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4177 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4178 checkGLcall("glScissor");
4179 } else {
4180 glScissor(This->stateBlock->viewport.X,
4181 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4182 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4183 This->stateBlock->viewport.Width,
4184 This->stateBlock->viewport.Height);
4185 checkGLcall("glScissor");
4188 /* Clear the selected rectangle (or full screen) */
4189 glClear(glMask);
4190 checkGLcall("glClear");
4192 /* Step to the next rectangle */
4193 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4196 /* Restore the old values (why..?) */
4197 if (Flags & WINED3DCLEAR_STENCIL) {
4198 glClearStencil(old_stencil_clear_value);
4199 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4201 if (Flags & WINED3DCLEAR_ZBUFFER) {
4202 glDepthMask(old_ztest);
4203 glClearDepth(old_z_clear_value);
4205 if (Flags & WINED3DCLEAR_TARGET) {
4206 glClearColor(old_color_clear_value[0],
4207 old_color_clear_value[1],
4208 old_color_clear_value[2],
4209 old_color_clear_value[3]);
4210 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4211 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4212 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4213 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4216 glDisable(GL_SCISSOR_TEST);
4217 checkGLcall("glDisable");
4218 LEAVE_GL();
4220 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4221 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4223 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4224 return WINED3D_OK;
4227 /*****
4228 * Drawing functions
4229 *****/
4230 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4231 UINT PrimitiveCount) {
4233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4234 This->stateBlock->streamIsUP = FALSE;
4236 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4237 debug_d3dprimitivetype(PrimitiveType),
4238 StartVertex, PrimitiveCount);
4240 if(This->stateBlock->loadBaseVertexIndex != 0) {
4241 This->stateBlock->loadBaseVertexIndex = 0;
4242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4244 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4245 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4246 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4247 return WINED3D_OK;
4250 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4251 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4252 WINED3DPRIMITIVETYPE PrimitiveType,
4253 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4256 UINT idxStride = 2;
4257 IWineD3DIndexBuffer *pIB;
4258 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4260 pIB = This->stateBlock->pIndexData;
4261 This->stateBlock->streamIsUP = FALSE;
4263 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4264 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4265 minIndex, NumVertices, startIndex, primCount);
4267 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4268 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4269 idxStride = 2;
4270 } else {
4271 idxStride = 4;
4274 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4275 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4279 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4280 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4282 return WINED3D_OK;
4285 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4286 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4287 UINT VertexStreamZeroStride) {
4288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4290 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4291 debug_d3dprimitivetype(PrimitiveType),
4292 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4294 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4295 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4296 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4297 This->stateBlock->streamIsUP = TRUE;
4298 This->stateBlock->loadBaseVertexIndex = 0;
4300 /* TODO: Only mark dirty if drawing from a different UP address */
4301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4303 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4304 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4306 /* MSDN specifies stream zero settings must be set to NULL */
4307 This->stateBlock->streamStride[0] = 0;
4308 This->stateBlock->streamSource[0] = NULL;
4310 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4311 * the new stream sources or use UP drawing again
4313 return WINED3D_OK;
4316 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4317 UINT MinVertexIndex, UINT NumVertices,
4318 UINT PrimitiveCount, CONST void* pIndexData,
4319 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4320 UINT VertexStreamZeroStride) {
4321 int idxStride;
4322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4324 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4325 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4326 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4327 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4329 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4330 idxStride = 2;
4331 } else {
4332 idxStride = 4;
4335 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4336 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4337 This->stateBlock->streamIsUP = TRUE;
4338 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4340 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4341 This->stateBlock->baseVertexIndex = 0;
4342 This->stateBlock->loadBaseVertexIndex = 0;
4343 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4346 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4348 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4349 This->stateBlock->streamSource[0] = NULL;
4350 This->stateBlock->streamStride[0] = 0;
4351 This->stateBlock->pIndexData = NULL;
4352 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4353 * SetStreamSource to specify a vertex buffer
4356 return WINED3D_OK;
4359 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4362 /* Mark the state dirty until we have nicer tracking
4363 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4364 * that value.
4366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4367 This->stateBlock->baseVertexIndex = 0;
4368 This->up_strided = DrawPrimStrideData;
4369 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4370 This->up_strided = NULL;
4371 return WINED3D_OK;
4373 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4374 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4376 HRESULT hr = WINED3D_OK;
4377 WINED3DRESOURCETYPE sourceType;
4378 WINED3DRESOURCETYPE destinationType;
4379 int i ,levels;
4381 /* TODO: think about moving the code into IWineD3DBaseTexture */
4383 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4385 /* verify that the source and destination textures aren't NULL */
4386 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4387 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4388 This, pSourceTexture, pDestinationTexture);
4389 hr = WINED3DERR_INVALIDCALL;
4392 if (pSourceTexture == pDestinationTexture) {
4393 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4394 This, pSourceTexture, pDestinationTexture);
4395 hr = WINED3DERR_INVALIDCALL;
4397 /* Verify that the source and destination textures are the same type */
4398 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4399 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4401 if (sourceType != destinationType) {
4402 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4403 This);
4404 hr = WINED3DERR_INVALIDCALL;
4407 /* check that both textures have the identical numbers of levels */
4408 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4409 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4410 hr = WINED3DERR_INVALIDCALL;
4413 if (WINED3D_OK == hr) {
4415 /* Make sure that the destination texture is loaded */
4416 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4418 /* Update every surface level of the texture */
4419 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4421 switch (sourceType) {
4422 case WINED3DRTYPE_TEXTURE:
4424 IWineD3DSurface *srcSurface;
4425 IWineD3DSurface *destSurface;
4427 for (i = 0 ; i < levels ; ++i) {
4428 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4429 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4430 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4431 IWineD3DSurface_Release(srcSurface);
4432 IWineD3DSurface_Release(destSurface);
4433 if (WINED3D_OK != hr) {
4434 WARN("(%p) : Call to update surface failed\n", This);
4435 return hr;
4439 break;
4440 case WINED3DRTYPE_CUBETEXTURE:
4442 IWineD3DSurface *srcSurface;
4443 IWineD3DSurface *destSurface;
4444 WINED3DCUBEMAP_FACES faceType;
4446 for (i = 0 ; i < levels ; ++i) {
4447 /* Update each cube face */
4448 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4449 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4450 if (WINED3D_OK != hr) {
4451 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4452 } else {
4453 TRACE("Got srcSurface %p\n", srcSurface);
4455 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4456 if (WINED3D_OK != hr) {
4457 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4458 } else {
4459 TRACE("Got desrSurface %p\n", destSurface);
4461 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4462 IWineD3DSurface_Release(srcSurface);
4463 IWineD3DSurface_Release(destSurface);
4464 if (WINED3D_OK != hr) {
4465 WARN("(%p) : Call to update surface failed\n", This);
4466 return hr;
4471 break;
4472 #if 0 /* TODO: Add support for volume textures */
4473 case WINED3DRTYPE_VOLUMETEXTURE:
4475 IWineD3DVolume srcVolume = NULL;
4476 IWineD3DSurface destVolume = NULL;
4478 for (i = 0 ; i < levels ; ++i) {
4479 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4480 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4481 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4482 IWineD3DVolume_Release(srcSurface);
4483 IWineD3DVolume_Release(destSurface);
4484 if (WINED3D_OK != hr) {
4485 WARN("(%p) : Call to update volume failed\n", This);
4486 return hr;
4490 break;
4491 #endif
4492 default:
4493 FIXME("(%p) : Unsupported source and destination type\n", This);
4494 hr = WINED3DERR_INVALIDCALL;
4498 return hr;
4501 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4502 IWineD3DSwapChain *swapChain;
4503 HRESULT hr;
4504 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4505 if(hr == WINED3D_OK) {
4506 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4507 IWineD3DSwapChain_Release(swapChain);
4509 return hr;
4512 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4514 /* return a sensible default */
4515 *pNumPasses = 1;
4516 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4517 FIXME("(%p) : stub\n", This);
4518 return WINED3D_OK;
4521 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4523 int j;
4524 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4525 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4526 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4527 return WINED3DERR_INVALIDCALL;
4529 for (j = 0; j < 256; ++j) {
4530 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4531 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4532 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4533 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4535 TRACE("(%p) : returning\n", This);
4536 return WINED3D_OK;
4539 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4541 int j;
4542 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4543 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4544 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4545 return WINED3DERR_INVALIDCALL;
4547 for (j = 0; j < 256; ++j) {
4548 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4549 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4550 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4551 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4553 TRACE("(%p) : returning\n", This);
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4560 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4561 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4562 return WINED3DERR_INVALIDCALL;
4564 /*TODO: stateblocks */
4565 This->currentPalette = PaletteNumber;
4566 TRACE("(%p) : returning\n", This);
4567 return WINED3D_OK;
4570 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 if (PaletteNumber == NULL) {
4573 WARN("(%p) : returning Invalid Call\n", This);
4574 return WINED3DERR_INVALIDCALL;
4576 /*TODO: stateblocks */
4577 *PaletteNumber = This->currentPalette;
4578 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4579 return WINED3D_OK;
4582 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4584 static BOOL showFixmes = TRUE;
4585 if (showFixmes) {
4586 FIXME("(%p) : stub\n", This);
4587 showFixmes = FALSE;
4590 This->softwareVertexProcessing = bSoftware;
4591 return WINED3D_OK;
4595 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4597 static BOOL showFixmes = TRUE;
4598 if (showFixmes) {
4599 FIXME("(%p) : stub\n", This);
4600 showFixmes = FALSE;
4602 return This->softwareVertexProcessing;
4606 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 IWineD3DSwapChain *swapChain;
4609 HRESULT hr;
4611 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4613 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4614 if(hr == WINED3D_OK){
4615 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4616 IWineD3DSwapChain_Release(swapChain);
4617 }else{
4618 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4620 return hr;
4624 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4626 static BOOL showfixmes = TRUE;
4627 if(nSegments != 0.0f) {
4628 if( showfixmes) {
4629 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4630 showfixmes = FALSE;
4633 return WINED3D_OK;
4636 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 static BOOL showfixmes = TRUE;
4639 if( showfixmes) {
4640 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4641 showfixmes = FALSE;
4643 return 0.0f;
4646 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4648 /** TODO: remove casts to IWineD3DSurfaceImpl
4649 * NOTE: move code to surface to accomplish this
4650 ****************************************/
4651 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4652 int srcWidth, srcHeight;
4653 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4654 WINED3DFORMAT destFormat, srcFormat;
4655 UINT destSize;
4656 int srcLeft, destLeft, destTop;
4657 WINED3DPOOL srcPool, destPool;
4658 int offset = 0;
4659 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4660 glDescriptor *glDescription = NULL;
4661 GLenum textureDimensions = GL_TEXTURE_2D;
4662 IWineD3DBaseTexture *baseTexture;
4664 WINED3DSURFACE_DESC winedesc;
4666 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4667 memset(&winedesc, 0, sizeof(winedesc));
4668 winedesc.Width = &srcSurfaceWidth;
4669 winedesc.Height = &srcSurfaceHeight;
4670 winedesc.Pool = &srcPool;
4671 winedesc.Format = &srcFormat;
4673 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4675 winedesc.Width = &destSurfaceWidth;
4676 winedesc.Height = &destSurfaceHeight;
4677 winedesc.Pool = &destPool;
4678 winedesc.Format = &destFormat;
4679 winedesc.Size = &destSize;
4681 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4683 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4684 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4685 return WINED3DERR_INVALIDCALL;
4688 if (destFormat == WINED3DFMT_UNKNOWN) {
4689 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4690 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4692 /* Get the update surface description */
4693 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4696 /* Make sure the surface is loaded and up to date */
4697 IWineD3DSurface_PreLoad(pDestinationSurface);
4699 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4701 ENTER_GL();
4703 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4704 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4705 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4706 srcLeft = pSourceRect ? pSourceRect->left : 0;
4707 destLeft = pDestPoint ? pDestPoint->x : 0;
4708 destTop = pDestPoint ? pDestPoint->y : 0;
4711 /* This function doesn't support compressed textures
4712 the pitch is just bytesPerPixel * width */
4713 if(srcWidth != srcSurfaceWidth || srcLeft ){
4714 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4715 offset += srcLeft * pSrcSurface->bytesPerPixel;
4716 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4718 /* TODO DXT formats */
4720 if(pSourceRect != NULL && pSourceRect->top != 0){
4721 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4723 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4724 ,This
4725 ,glDescription->level
4726 ,destLeft
4727 ,destTop
4728 ,srcWidth
4729 ,srcHeight
4730 ,glDescription->glFormat
4731 ,glDescription->glType
4732 ,IWineD3DSurface_GetData(pSourceSurface)
4735 /* Sanity check */
4736 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4738 /* need to lock the surface to get the data */
4739 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4742 /* TODO: Cube and volume support */
4743 if(rowoffset != 0){
4744 /* not a whole row so we have to do it a line at a time */
4745 int j;
4747 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4748 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4750 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4752 glTexSubImage2D(glDescription->target
4753 ,glDescription->level
4754 ,destLeft
4756 ,srcWidth
4758 ,glDescription->glFormat
4759 ,glDescription->glType
4760 ,data /* could be quicker using */
4762 data += rowoffset;
4765 } else { /* Full width, so just write out the whole texture */
4767 if (WINED3DFMT_DXT1 == destFormat ||
4768 WINED3DFMT_DXT2 == destFormat ||
4769 WINED3DFMT_DXT3 == destFormat ||
4770 WINED3DFMT_DXT4 == destFormat ||
4771 WINED3DFMT_DXT5 == destFormat) {
4772 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4773 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4774 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4775 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4776 } if (destFormat != srcFormat) {
4777 FIXME("Updating mixed format compressed texture is not curretly support\n");
4778 } else {
4779 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4780 glDescription->level,
4781 glDescription->glFormatInternal,
4782 srcWidth,
4783 srcHeight,
4785 destSize,
4786 IWineD3DSurface_GetData(pSourceSurface));
4788 } else {
4789 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4793 } else {
4794 glTexSubImage2D(glDescription->target
4795 ,glDescription->level
4796 ,destLeft
4797 ,destTop
4798 ,srcWidth
4799 ,srcHeight
4800 ,glDescription->glFormat
4801 ,glDescription->glType
4802 ,IWineD3DSurface_GetData(pSourceSurface)
4806 checkGLcall("glTexSubImage2D");
4807 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4809 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4810 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4811 * surface bigger than it needs to be hmm.. */
4812 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4813 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4814 IWineD3DBaseTexture_Release(baseTexture);
4817 glDisable(textureDimensions); /* This needs to be managed better.... */
4818 LEAVE_GL();
4820 return WINED3D_OK;
4823 /* Implementation details at http://developer.nvidia.com/attach/6494
4825 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4826 hmm.. no longer supported use
4827 OpenGL evaluators or tessellate surfaces within your application.
4830 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4831 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4834 FIXME("(%p) : Stub\n", This);
4835 return WINED3D_OK;
4839 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4840 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4843 FIXME("(%p) : Stub\n", This);
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4849 TRACE("(%p) Handle(%d)\n", This, Handle);
4850 FIXME("(%p) : Stub\n", This);
4851 return WINED3D_OK;
4854 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4856 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4857 DDBLTFX BltFx;
4858 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4860 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4861 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4862 return WINED3DERR_INVALIDCALL;
4865 /* Just forward this to the DirectDraw blitting engine */
4866 memset(&BltFx, 0, sizeof(BltFx));
4867 BltFx.dwSize = sizeof(BltFx);
4868 BltFx.u5.dwFillColor = color;
4869 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4872 /* rendertarget and deptth stencil functions */
4873 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4876 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4877 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4878 return WINED3DERR_INVALIDCALL;
4881 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4882 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4883 /* Note inc ref on returned surface */
4884 if(*ppRenderTarget != NULL)
4885 IWineD3DSurface_AddRef(*ppRenderTarget);
4886 return WINED3D_OK;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4892 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4893 IWineD3DSwapChainImpl *Swapchain;
4894 HRESULT hr;
4896 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4898 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4899 if(hr != WINED3D_OK) {
4900 ERR("Can't get the swapchain\n");
4901 return hr;
4904 /* Make sure to release the swapchain */
4905 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4907 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4908 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4909 return WINED3DERR_INVALIDCALL;
4911 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4912 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4913 return WINED3DERR_INVALIDCALL;
4916 if(Swapchain->frontBuffer != Front) {
4917 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4919 if(Swapchain->frontBuffer)
4920 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4921 Swapchain->frontBuffer = Front;
4923 if(Swapchain->frontBuffer) {
4924 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4928 if(Back && !Swapchain->backBuffer) {
4929 /* We need memory for the back buffer array - only one back buffer this way */
4930 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4931 if(!Swapchain->backBuffer) {
4932 ERR("Out of memory\n");
4933 return E_OUTOFMEMORY;
4937 if(Swapchain->backBuffer[0] != Back) {
4938 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4939 ENTER_GL();
4940 if(!Swapchain->backBuffer[0]) {
4941 /* GL was told to draw to the front buffer at creation,
4942 * undo that
4944 glDrawBuffer(GL_BACK);
4945 checkGLcall("glDrawBuffer(GL_BACK)");
4946 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4947 Swapchain->presentParms.BackBufferCount = 1;
4948 } else if (!Back) {
4949 /* That makes problems - disable for now */
4950 /* glDrawBuffer(GL_FRONT); */
4951 checkGLcall("glDrawBuffer(GL_FRONT)");
4952 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4953 Swapchain->presentParms.BackBufferCount = 0;
4955 LEAVE_GL();
4957 if(Swapchain->backBuffer[0])
4958 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4959 Swapchain->backBuffer[0] = Back;
4961 if(Swapchain->backBuffer[0]) {
4962 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4963 } else {
4964 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
4969 return WINED3D_OK;
4972 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
4973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4974 *ppZStencilSurface = This->depthStencilBuffer;
4975 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
4977 if(*ppZStencilSurface != NULL) {
4978 /* Note inc ref on returned surface */
4979 IWineD3DSurface_AddRef(*ppZStencilSurface);
4981 return WINED3D_OK;
4984 static void bind_fbo(IWineD3DDevice *iface) {
4985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4987 if (!This->fbo) {
4988 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
4989 checkGLcall("glGenFramebuffersEXT()");
4991 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
4992 checkGLcall("glBindFramebuffer()");
4995 /* TODO: Handle stencil attachments */
4996 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5000 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5002 bind_fbo(iface);
5004 if (depth_stencil_impl) {
5005 GLenum texttarget, target;
5006 GLint old_binding = 0;
5008 IWineD3DSurface_PreLoad(depth_stencil);
5009 texttarget = depth_stencil_impl->glDescription.target;
5010 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5012 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5013 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5014 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5015 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5016 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5017 glBindTexture(target, old_binding);
5019 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5020 checkGLcall("glFramebufferTexture2DEXT()");
5021 } else {
5022 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5023 checkGLcall("glFramebufferTexture2DEXT()");
5026 if (!This->render_offscreen) {
5027 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5028 checkGLcall("glBindFramebuffer()");
5032 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5034 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5036 if (idx >= GL_LIMITS(buffers)) {
5037 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5040 bind_fbo(iface);
5042 if (rtimpl) {
5043 GLenum texttarget, target;
5044 GLint old_binding = 0;
5046 IWineD3DSurface_PreLoad(render_target);
5047 texttarget = rtimpl->glDescription.target;
5048 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5050 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5051 glBindTexture(target, rtimpl->glDescription.textureName);
5052 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5053 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5054 glBindTexture(target, old_binding);
5056 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5057 checkGLcall("glFramebufferTexture2DEXT()");
5059 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5060 } else {
5061 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5062 checkGLcall("glFramebufferTexture2DEXT()");
5064 This->draw_buffers[idx] = GL_NONE;
5067 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5068 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5069 checkGLcall("glDrawBuffers()");
5072 if (!This->render_offscreen) {
5073 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5074 checkGLcall("glBindFramebuffer()");
5078 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 WINED3DVIEWPORT viewport;
5082 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5084 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5085 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5086 return WINED3DERR_INVALIDCALL;
5089 /* MSDN says that null disables the render target
5090 but a device must always be associated with a render target
5091 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5093 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5094 for more details
5096 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5097 FIXME("Trying to set render target 0 to NULL\n");
5098 return WINED3DERR_INVALIDCALL;
5100 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5101 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);
5102 return WINED3DERR_INVALIDCALL;
5105 /* If we are trying to set what we already have, don't bother */
5106 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5107 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5108 return WINED3D_OK;
5110 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5111 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5112 This->render_targets[RenderTargetIndex] = pRenderTarget;
5114 /* Render target 0 is special */
5115 if(RenderTargetIndex == 0) {
5116 /* Finally, reset the viewport as the MSDN states. */
5117 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5118 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5119 viewport.X = 0;
5120 viewport.Y = 0;
5121 viewport.MaxZ = 1.0f;
5122 viewport.MinZ = 0.0f;
5123 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5125 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5126 * ctx properly.
5127 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5128 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5130 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5131 } else {
5132 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5133 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5135 return WINED3D_OK;
5138 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5140 HRESULT hr = WINED3D_OK;
5141 IWineD3DSurface *tmp;
5143 TRACE("(%p) Swapping z-buffer\n",This);
5145 if (pNewZStencil == This->stencilBufferTarget) {
5146 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5147 } else {
5148 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5149 * depending on the renter target implementation being used.
5150 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5151 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5152 * stencil buffer and incure an extra memory overhead
5153 ******************************************************/
5156 tmp = This->stencilBufferTarget;
5157 This->stencilBufferTarget = pNewZStencil;
5158 /* should we be calling the parent or the wined3d surface? */
5159 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5160 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5161 hr = WINED3D_OK;
5162 /** TODO: glEnable/glDisable on depth/stencil depending on
5163 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5164 **********************************************************/
5165 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5166 set_depth_stencil_fbo(iface, pNewZStencil);
5170 return hr;
5173 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5174 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5176 /* TODO: the use of Impl is deprecated. */
5177 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5179 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5181 /* some basic validation checks */
5182 if(This->cursorTexture) {
5183 ENTER_GL();
5184 glDeleteTextures(1, &This->cursorTexture);
5185 LEAVE_GL();
5186 This->cursorTexture = 0;
5189 if(pCursorBitmap) {
5190 /* MSDN: Cursor must be A8R8G8B8 */
5191 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5192 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5193 return WINED3DERR_INVALIDCALL;
5196 /* MSDN: Cursor must be smaller than the display mode */
5197 if(pSur->currentDesc.Width > This->ddraw_width ||
5198 pSur->currentDesc.Height > This->ddraw_height) {
5199 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);
5200 return WINED3DERR_INVALIDCALL;
5203 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5204 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5205 * Texture and Blitting code to draw the cursor
5207 pSur->Flags |= SFLAG_FORCELOAD;
5208 IWineD3DSurface_PreLoad(pCursorBitmap);
5209 pSur->Flags &= ~SFLAG_FORCELOAD;
5210 /* Do not store the surface's pointer because the application may release
5211 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5212 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5214 This->cursorTexture = pSur->glDescription.textureName;
5215 This->cursorWidth = pSur->currentDesc.Width;
5216 This->cursorHeight = pSur->currentDesc.Height;
5217 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5220 This->xHotSpot = XHotSpot;
5221 This->yHotSpot = YHotSpot;
5222 return WINED3D_OK;
5225 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5227 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5229 This->xScreenSpace = XScreenSpace;
5230 This->yScreenSpace = YScreenSpace;
5232 return;
5236 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5238 BOOL oldVisible = This->bCursorVisible;
5239 TRACE("(%p) : visible(%d)\n", This, bShow);
5241 if(This->cursorTexture)
5242 This->bCursorVisible = bShow;
5244 return oldVisible;
5247 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5249 TRACE("(%p) : state (%u)\n", This, This->state);
5250 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5251 switch (This->state) {
5252 case WINED3D_OK:
5253 return WINED3D_OK;
5254 case WINED3DERR_DEVICELOST:
5256 ResourceList *resourceList = This->resources;
5257 while (NULL != resourceList) {
5258 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5259 return WINED3DERR_DEVICENOTRESET;
5260 resourceList = resourceList->next;
5262 return WINED3DERR_DEVICELOST;
5264 case WINED3DERR_DRIVERINTERNALERROR:
5265 return WINED3DERR_DRIVERINTERNALERROR;
5268 /* Unknown state */
5269 return WINED3DERR_DRIVERINTERNALERROR;
5273 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5275 /** FIXME: Resource tracking needs to be done,
5276 * The closes we can do to this is set the priorities of all managed textures low
5277 * and then reset them.
5278 ***********************************************************/
5279 FIXME("(%p) : stub\n", This);
5280 return WINED3D_OK;
5283 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5284 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5286 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5287 if(surface->Flags & SFLAG_DIBSECTION) {
5288 /* Release the DC */
5289 SelectObject(surface->hDC, surface->dib.holdbitmap);
5290 DeleteDC(surface->hDC);
5291 /* Release the DIB section */
5292 DeleteObject(surface->dib.DIBsection);
5293 surface->dib.bitmap_data = NULL;
5294 surface->resource.allocatedMemory = NULL;
5295 surface->Flags &= ~SFLAG_DIBSECTION;
5297 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5298 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5299 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5300 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5301 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5302 } else {
5303 surface->pow2Width = surface->pow2Height = 1;
5304 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5305 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5307 if(surface->glDescription.textureName) {
5308 ENTER_GL();
5309 glDeleteTextures(1, &surface->glDescription.textureName);
5310 LEAVE_GL();
5311 surface->glDescription.textureName = 0;
5313 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5314 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5315 surface->Flags |= SFLAG_NONPOW2;
5316 } else {
5317 surface->Flags &= ~SFLAG_NONPOW2;
5319 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5320 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5323 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5325 IWineD3DSwapChainImpl *swapchain;
5326 HRESULT hr;
5327 BOOL DisplayModeChanged = FALSE;
5328 WINED3DDISPLAYMODE mode;
5329 TRACE("(%p)\n", This);
5331 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5332 if(FAILED(hr)) {
5333 ERR("Failed to get the first implicit swapchain\n");
5334 return hr;
5337 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5338 * on an existing gl context, so there's no real need for recreation.
5340 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5342 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5344 TRACE("New params:\n");
5345 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5346 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5347 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5348 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5349 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5350 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5351 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5352 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5353 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5354 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5355 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5356 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5357 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5359 /* No special treatment of these parameters. Just store them */
5360 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5361 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5362 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5363 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5365 /* What to do about these? */
5366 if(pPresentationParameters->BackBufferCount != 0 &&
5367 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5368 ERR("Cannot change the back buffer count yet\n");
5370 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5371 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5372 ERR("Cannot change the back buffer format yet\n");
5374 if(pPresentationParameters->hDeviceWindow != NULL &&
5375 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5376 ERR("Cannot change the device window yet\n");
5378 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5379 ERR("What do do about a changed auto depth stencil parameter?\n");
5382 if(pPresentationParameters->Windowed) {
5383 mode.Width = swapchain->orig_width;
5384 mode.Height = swapchain->orig_height;
5385 mode.RefreshRate = 0;
5386 mode.Format = swapchain->presentParms.BackBufferFormat;
5387 } else {
5388 mode.Width = pPresentationParameters->BackBufferWidth;
5389 mode.Height = pPresentationParameters->BackBufferHeight;
5390 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5391 mode.Format = swapchain->presentParms.BackBufferFormat;
5394 /* Should Width == 800 && Height == 0 set 800x600? */
5395 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5396 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5397 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5399 WINED3DVIEWPORT vp;
5400 int i;
5402 vp.X = 0;
5403 vp.Y = 0;
5404 vp.Width = pPresentationParameters->BackBufferWidth;
5405 vp.Height = pPresentationParameters->BackBufferHeight;
5406 vp.MinZ = 0;
5407 vp.MaxZ = 1;
5409 if(!pPresentationParameters->Windowed) {
5410 DisplayModeChanged = TRUE;
5412 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5413 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5415 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5416 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5417 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5420 /* Now set the new viewport */
5421 IWineD3DDevice_SetViewport(iface, &vp);
5424 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5425 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5426 DisplayModeChanged) {
5428 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5429 if(!pPresentationParameters->Windowed) {
5430 IWineD3DDevice_SetFullscreen(iface, TRUE);
5433 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5435 /* Switching out of fullscreen mode? First set the original res, then change the window */
5436 if(pPresentationParameters->Windowed) {
5437 IWineD3DDevice_SetFullscreen(iface, FALSE);
5439 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5442 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5443 return WINED3D_OK;
5446 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5448 /** FIXME: always true at the moment **/
5449 if(!bEnableDialogs) {
5450 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5452 return WINED3D_OK;
5456 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5458 TRACE("(%p) : pParameters %p\n", This, pParameters);
5460 *pParameters = This->createParms;
5461 return WINED3D_OK;
5464 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5465 IWineD3DSwapChain *swapchain;
5466 HRESULT hrc = WINED3D_OK;
5468 TRACE("Relaying to swapchain\n");
5470 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5471 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5472 IWineD3DSwapChain_Release(swapchain);
5474 return;
5477 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5478 IWineD3DSwapChain *swapchain;
5479 HRESULT hrc = WINED3D_OK;
5481 TRACE("Relaying to swapchain\n");
5483 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5484 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5485 IWineD3DSwapChain_Release(swapchain);
5487 return;
5491 /** ********************************************************
5492 * Notification functions
5493 ** ********************************************************/
5494 /** This function must be called in the release of a resource when ref == 0,
5495 * the contents of resource must still be correct,
5496 * any handels to other resource held by the caller must be closed
5497 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5498 *****************************************************/
5499 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5501 ResourceList* resourceList;
5503 TRACE("(%p) : resource %p\n", This, resource);
5504 #if 0
5505 EnterCriticalSection(&resourceStoreCriticalSection);
5506 #endif
5507 /* add a new texture to the frot of the linked list */
5508 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5509 resourceList->resource = resource;
5511 /* Get the old head */
5512 resourceList->next = This->resources;
5514 This->resources = resourceList;
5515 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5517 #if 0
5518 LeaveCriticalSection(&resourceStoreCriticalSection);
5519 #endif
5520 return;
5523 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5525 ResourceList* resourceList = NULL;
5526 ResourceList* previousResourceList = NULL;
5528 TRACE("(%p) : resource %p\n", This, resource);
5530 #if 0
5531 EnterCriticalSection(&resourceStoreCriticalSection);
5532 #endif
5533 resourceList = This->resources;
5535 while (resourceList != NULL) {
5536 if(resourceList->resource == resource) break;
5537 previousResourceList = resourceList;
5538 resourceList = resourceList->next;
5541 if (resourceList == NULL) {
5542 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5543 #if 0
5544 LeaveCriticalSection(&resourceStoreCriticalSection);
5545 #endif
5546 return;
5547 } else {
5548 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5550 /* make sure we don't leave a hole in the list */
5551 if (previousResourceList != NULL) {
5552 previousResourceList->next = resourceList->next;
5553 } else {
5554 This->resources = resourceList->next;
5557 #if 0
5558 LeaveCriticalSection(&resourceStoreCriticalSection);
5559 #endif
5560 return;
5564 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5566 int counter;
5568 TRACE("(%p) : resource %p\n", This, resource);
5569 switch(IWineD3DResource_GetType(resource)){
5570 case WINED3DRTYPE_SURFACE:
5571 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5572 break;
5573 case WINED3DRTYPE_TEXTURE:
5574 case WINED3DRTYPE_CUBETEXTURE:
5575 case WINED3DRTYPE_VOLUMETEXTURE:
5576 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5577 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5578 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5579 This->stateBlock->textures[counter] = NULL;
5581 if (This->updateStateBlock != This->stateBlock ){
5582 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5583 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5584 This->updateStateBlock->textures[counter] = NULL;
5588 break;
5589 case WINED3DRTYPE_VOLUME:
5590 /* TODO: nothing really? */
5591 break;
5592 case WINED3DRTYPE_VERTEXBUFFER:
5593 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5595 int streamNumber;
5596 TRACE("Cleaning up stream pointers\n");
5598 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5599 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5600 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5602 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5603 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5604 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5605 This->updateStateBlock->streamSource[streamNumber] = 0;
5606 /* Set changed flag? */
5609 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) */
5610 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5611 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5612 This->stateBlock->streamSource[streamNumber] = 0;
5615 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5616 else { /* This shouldn't happen */
5617 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5619 #endif
5623 break;
5624 case WINED3DRTYPE_INDEXBUFFER:
5625 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5626 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5627 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5628 This->updateStateBlock->pIndexData = NULL;
5631 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5632 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5633 This->stateBlock->pIndexData = NULL;
5637 break;
5638 default:
5639 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5640 break;
5644 /* Remove the resoruce from the resourceStore */
5645 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5647 TRACE("Resource released\n");
5651 /**********************************************************
5652 * IWineD3DDevice VTbl follows
5653 **********************************************************/
5655 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5657 /*** IUnknown methods ***/
5658 IWineD3DDeviceImpl_QueryInterface,
5659 IWineD3DDeviceImpl_AddRef,
5660 IWineD3DDeviceImpl_Release,
5661 /*** IWineD3DDevice methods ***/
5662 IWineD3DDeviceImpl_GetParent,
5663 /*** Creation methods**/
5664 IWineD3DDeviceImpl_CreateVertexBuffer,
5665 IWineD3DDeviceImpl_CreateIndexBuffer,
5666 IWineD3DDeviceImpl_CreateStateBlock,
5667 IWineD3DDeviceImpl_CreateSurface,
5668 IWineD3DDeviceImpl_CreateTexture,
5669 IWineD3DDeviceImpl_CreateVolumeTexture,
5670 IWineD3DDeviceImpl_CreateVolume,
5671 IWineD3DDeviceImpl_CreateCubeTexture,
5672 IWineD3DDeviceImpl_CreateQuery,
5673 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5674 IWineD3DDeviceImpl_CreateVertexDeclaration,
5675 IWineD3DDeviceImpl_CreateVertexShader,
5676 IWineD3DDeviceImpl_CreatePixelShader,
5677 IWineD3DDeviceImpl_CreatePalette,
5678 /*** Odd functions **/
5679 IWineD3DDeviceImpl_Init3D,
5680 IWineD3DDeviceImpl_Uninit3D,
5681 IWineD3DDeviceImpl_SetFullscreen,
5682 IWineD3DDeviceImpl_EvictManagedResources,
5683 IWineD3DDeviceImpl_GetAvailableTextureMem,
5684 IWineD3DDeviceImpl_GetBackBuffer,
5685 IWineD3DDeviceImpl_GetCreationParameters,
5686 IWineD3DDeviceImpl_GetDeviceCaps,
5687 IWineD3DDeviceImpl_GetDirect3D,
5688 IWineD3DDeviceImpl_GetDisplayMode,
5689 IWineD3DDeviceImpl_SetDisplayMode,
5690 IWineD3DDeviceImpl_GetHWND,
5691 IWineD3DDeviceImpl_SetHWND,
5692 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5693 IWineD3DDeviceImpl_GetRasterStatus,
5694 IWineD3DDeviceImpl_GetSwapChain,
5695 IWineD3DDeviceImpl_Reset,
5696 IWineD3DDeviceImpl_SetDialogBoxMode,
5697 IWineD3DDeviceImpl_SetCursorProperties,
5698 IWineD3DDeviceImpl_SetCursorPosition,
5699 IWineD3DDeviceImpl_ShowCursor,
5700 IWineD3DDeviceImpl_TestCooperativeLevel,
5701 /*** Getters and setters **/
5702 IWineD3DDeviceImpl_SetClipPlane,
5703 IWineD3DDeviceImpl_GetClipPlane,
5704 IWineD3DDeviceImpl_SetClipStatus,
5705 IWineD3DDeviceImpl_GetClipStatus,
5706 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5707 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5708 IWineD3DDeviceImpl_SetDepthStencilSurface,
5709 IWineD3DDeviceImpl_GetDepthStencilSurface,
5710 IWineD3DDeviceImpl_SetFVF,
5711 IWineD3DDeviceImpl_GetFVF,
5712 IWineD3DDeviceImpl_SetGammaRamp,
5713 IWineD3DDeviceImpl_GetGammaRamp,
5714 IWineD3DDeviceImpl_SetIndices,
5715 IWineD3DDeviceImpl_GetIndices,
5716 IWineD3DDeviceImpl_SetBasevertexIndex,
5717 IWineD3DDeviceImpl_SetLight,
5718 IWineD3DDeviceImpl_GetLight,
5719 IWineD3DDeviceImpl_SetLightEnable,
5720 IWineD3DDeviceImpl_GetLightEnable,
5721 IWineD3DDeviceImpl_SetMaterial,
5722 IWineD3DDeviceImpl_GetMaterial,
5723 IWineD3DDeviceImpl_SetNPatchMode,
5724 IWineD3DDeviceImpl_GetNPatchMode,
5725 IWineD3DDeviceImpl_SetPaletteEntries,
5726 IWineD3DDeviceImpl_GetPaletteEntries,
5727 IWineD3DDeviceImpl_SetPixelShader,
5728 IWineD3DDeviceImpl_GetPixelShader,
5729 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5730 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5731 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5732 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5733 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5734 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5735 IWineD3DDeviceImpl_SetRenderState,
5736 IWineD3DDeviceImpl_GetRenderState,
5737 IWineD3DDeviceImpl_SetRenderTarget,
5738 IWineD3DDeviceImpl_GetRenderTarget,
5739 IWineD3DDeviceImpl_SetFrontBackBuffers,
5740 IWineD3DDeviceImpl_SetSamplerState,
5741 IWineD3DDeviceImpl_GetSamplerState,
5742 IWineD3DDeviceImpl_SetScissorRect,
5743 IWineD3DDeviceImpl_GetScissorRect,
5744 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5745 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5746 IWineD3DDeviceImpl_SetStreamSource,
5747 IWineD3DDeviceImpl_GetStreamSource,
5748 IWineD3DDeviceImpl_SetStreamSourceFreq,
5749 IWineD3DDeviceImpl_GetStreamSourceFreq,
5750 IWineD3DDeviceImpl_SetTexture,
5751 IWineD3DDeviceImpl_GetTexture,
5752 IWineD3DDeviceImpl_SetTextureStageState,
5753 IWineD3DDeviceImpl_GetTextureStageState,
5754 IWineD3DDeviceImpl_SetTransform,
5755 IWineD3DDeviceImpl_GetTransform,
5756 IWineD3DDeviceImpl_SetVertexDeclaration,
5757 IWineD3DDeviceImpl_GetVertexDeclaration,
5758 IWineD3DDeviceImpl_SetVertexShader,
5759 IWineD3DDeviceImpl_GetVertexShader,
5760 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5761 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5762 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5763 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5764 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5765 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5766 IWineD3DDeviceImpl_SetViewport,
5767 IWineD3DDeviceImpl_GetViewport,
5768 IWineD3DDeviceImpl_MultiplyTransform,
5769 IWineD3DDeviceImpl_ValidateDevice,
5770 IWineD3DDeviceImpl_ProcessVertices,
5771 /*** State block ***/
5772 IWineD3DDeviceImpl_BeginStateBlock,
5773 IWineD3DDeviceImpl_EndStateBlock,
5774 /*** Scene management ***/
5775 IWineD3DDeviceImpl_BeginScene,
5776 IWineD3DDeviceImpl_EndScene,
5777 IWineD3DDeviceImpl_Present,
5778 IWineD3DDeviceImpl_Clear,
5779 /*** Drawing ***/
5780 IWineD3DDeviceImpl_DrawPrimitive,
5781 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5782 IWineD3DDeviceImpl_DrawPrimitiveUP,
5783 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5784 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5785 IWineD3DDeviceImpl_DrawRectPatch,
5786 IWineD3DDeviceImpl_DrawTriPatch,
5787 IWineD3DDeviceImpl_DeletePatch,
5788 IWineD3DDeviceImpl_ColorFill,
5789 IWineD3DDeviceImpl_UpdateTexture,
5790 IWineD3DDeviceImpl_UpdateSurface,
5791 IWineD3DDeviceImpl_GetFrontBufferData,
5792 /*** object tracking ***/
5793 IWineD3DDeviceImpl_ResourceReleased
5797 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5798 WINED3DRS_ALPHABLENDENABLE ,
5799 WINED3DRS_ALPHAFUNC ,
5800 WINED3DRS_ALPHAREF ,
5801 WINED3DRS_ALPHATESTENABLE ,
5802 WINED3DRS_BLENDOP ,
5803 WINED3DRS_COLORWRITEENABLE ,
5804 WINED3DRS_DESTBLEND ,
5805 WINED3DRS_DITHERENABLE ,
5806 WINED3DRS_FILLMODE ,
5807 WINED3DRS_FOGDENSITY ,
5808 WINED3DRS_FOGEND ,
5809 WINED3DRS_FOGSTART ,
5810 WINED3DRS_LASTPIXEL ,
5811 WINED3DRS_SHADEMODE ,
5812 WINED3DRS_SRCBLEND ,
5813 WINED3DRS_STENCILENABLE ,
5814 WINED3DRS_STENCILFAIL ,
5815 WINED3DRS_STENCILFUNC ,
5816 WINED3DRS_STENCILMASK ,
5817 WINED3DRS_STENCILPASS ,
5818 WINED3DRS_STENCILREF ,
5819 WINED3DRS_STENCILWRITEMASK ,
5820 WINED3DRS_STENCILZFAIL ,
5821 WINED3DRS_TEXTUREFACTOR ,
5822 WINED3DRS_WRAP0 ,
5823 WINED3DRS_WRAP1 ,
5824 WINED3DRS_WRAP2 ,
5825 WINED3DRS_WRAP3 ,
5826 WINED3DRS_WRAP4 ,
5827 WINED3DRS_WRAP5 ,
5828 WINED3DRS_WRAP6 ,
5829 WINED3DRS_WRAP7 ,
5830 WINED3DRS_ZENABLE ,
5831 WINED3DRS_ZFUNC ,
5832 WINED3DRS_ZWRITEENABLE
5835 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5836 WINED3DTSS_ADDRESSW ,
5837 WINED3DTSS_ALPHAARG0 ,
5838 WINED3DTSS_ALPHAARG1 ,
5839 WINED3DTSS_ALPHAARG2 ,
5840 WINED3DTSS_ALPHAOP ,
5841 WINED3DTSS_BUMPENVLOFFSET ,
5842 WINED3DTSS_BUMPENVLSCALE ,
5843 WINED3DTSS_BUMPENVMAT00 ,
5844 WINED3DTSS_BUMPENVMAT01 ,
5845 WINED3DTSS_BUMPENVMAT10 ,
5846 WINED3DTSS_BUMPENVMAT11 ,
5847 WINED3DTSS_COLORARG0 ,
5848 WINED3DTSS_COLORARG1 ,
5849 WINED3DTSS_COLORARG2 ,
5850 WINED3DTSS_COLOROP ,
5851 WINED3DTSS_RESULTARG ,
5852 WINED3DTSS_TEXCOORDINDEX ,
5853 WINED3DTSS_TEXTURETRANSFORMFLAGS
5856 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5857 WINED3DSAMP_ADDRESSU ,
5858 WINED3DSAMP_ADDRESSV ,
5859 WINED3DSAMP_ADDRESSW ,
5860 WINED3DSAMP_BORDERCOLOR ,
5861 WINED3DSAMP_MAGFILTER ,
5862 WINED3DSAMP_MINFILTER ,
5863 WINED3DSAMP_MIPFILTER ,
5864 WINED3DSAMP_MIPMAPLODBIAS ,
5865 WINED3DSAMP_MAXMIPLEVEL ,
5866 WINED3DSAMP_MAXANISOTROPY ,
5867 WINED3DSAMP_SRGBTEXTURE ,
5868 WINED3DSAMP_ELEMENTINDEX
5871 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5872 WINED3DRS_AMBIENT ,
5873 WINED3DRS_AMBIENTMATERIALSOURCE ,
5874 WINED3DRS_CLIPPING ,
5875 WINED3DRS_CLIPPLANEENABLE ,
5876 WINED3DRS_COLORVERTEX ,
5877 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5878 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5879 WINED3DRS_FOGDENSITY ,
5880 WINED3DRS_FOGEND ,
5881 WINED3DRS_FOGSTART ,
5882 WINED3DRS_FOGTABLEMODE ,
5883 WINED3DRS_FOGVERTEXMODE ,
5884 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5885 WINED3DRS_LIGHTING ,
5886 WINED3DRS_LOCALVIEWER ,
5887 WINED3DRS_MULTISAMPLEANTIALIAS ,
5888 WINED3DRS_MULTISAMPLEMASK ,
5889 WINED3DRS_NORMALIZENORMALS ,
5890 WINED3DRS_PATCHEDGESTYLE ,
5891 WINED3DRS_POINTSCALE_A ,
5892 WINED3DRS_POINTSCALE_B ,
5893 WINED3DRS_POINTSCALE_C ,
5894 WINED3DRS_POINTSCALEENABLE ,
5895 WINED3DRS_POINTSIZE ,
5896 WINED3DRS_POINTSIZE_MAX ,
5897 WINED3DRS_POINTSIZE_MIN ,
5898 WINED3DRS_POINTSPRITEENABLE ,
5899 WINED3DRS_RANGEFOGENABLE ,
5900 WINED3DRS_SPECULARMATERIALSOURCE ,
5901 WINED3DRS_TWEENFACTOR ,
5902 WINED3DRS_VERTEXBLEND
5905 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5906 WINED3DTSS_TEXCOORDINDEX ,
5907 WINED3DTSS_TEXTURETRANSFORMFLAGS
5910 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5911 WINED3DSAMP_DMAPOFFSET
5914 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5915 DWORD rep = StateTable[state].representative;
5916 DWORD idx;
5917 BYTE shift;
5918 UINT i;
5919 WineD3DContext *context;
5921 if(!rep) return;
5922 for(i = 0; i < This->numContexts; i++) {
5923 context = This->contexts[i];
5924 if(isStateDirty(context, rep)) continue;
5926 context->dirtyArray[context->numDirtyEntries++] = rep;
5927 idx = rep >> 5;
5928 shift = rep & 0x1f;
5929 context->isStateDirty[idx] |= (1 << shift);