wined3d: Remove stream flags from GetStreamSource.
[wine/wine-gecko.git] / dlls / wined3d / device.c
blob2799ffd39bbefc90e1c95df55e34c8c3748696f5
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_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
1826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1828 DEVMODEW DevModeW;
1829 int i;
1830 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
1832 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
1834 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
1835 /* Ignore some modes if a description was passed */
1836 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
1837 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
1838 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
1840 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
1842 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
1843 return WINED3D_OK;
1846 return WINED3D_OK;
1849 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1850 DEVMODEW devmode;
1851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1852 LONG ret;
1853 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1854 RECT clip_rc;
1856 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1858 /* Resize the screen even without a window:
1859 * The app could have unset it with SetCooperativeLevel, but not called
1860 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1861 * but we don't have any hwnd
1864 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1865 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1866 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1867 devmode.dmPelsWidth = pMode->Width;
1868 devmode.dmPelsHeight = pMode->Height;
1870 devmode.dmDisplayFrequency = pMode->RefreshRate;
1871 if (pMode->RefreshRate != 0) {
1872 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1875 /* Only change the mode if necessary */
1876 if( (This->ddraw_width == pMode->Width) &&
1877 (This->ddraw_height == pMode->Height) &&
1878 (This->ddraw_format == pMode->Format) &&
1879 (pMode->RefreshRate == 0) ) {
1880 return WINED3D_OK;
1883 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1884 if (ret != DISP_CHANGE_SUCCESSFUL) {
1885 if(devmode.dmDisplayFrequency != 0) {
1886 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1887 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1888 devmode.dmDisplayFrequency = 0;
1889 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1891 if(ret != DISP_CHANGE_SUCCESSFUL) {
1892 return DDERR_INVALIDMODE;
1896 /* Store the new values */
1897 This->ddraw_width = pMode->Width;
1898 This->ddraw_height = pMode->Height;
1899 This->ddraw_format = pMode->Format;
1901 /* Only do this with a window of course */
1902 if(This->ddraw_window)
1903 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1905 /* And finally clip mouse to our screen */
1906 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1907 ClipCursor(&clip_rc);
1909 return WINED3D_OK;
1912 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1914 *ppD3D= This->wineD3D;
1915 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1916 IWineD3D_AddRef(*ppD3D);
1917 return WINED3D_OK;
1920 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1921 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1922 * into the video ram as possible and seeing how many fit
1923 * you can also get the correct initial value from nvidia and ATI's driver via X
1924 * texture memory is video memory + AGP memory
1925 *******************/
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1927 static BOOL showfixmes = TRUE;
1928 if (showfixmes) {
1929 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1930 (wined3d_settings.emulated_textureram/(1024*1024)),
1931 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1932 showfixmes = FALSE;
1934 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1935 (wined3d_settings.emulated_textureram/(1024*1024)),
1936 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1937 /* return simulated texture memory left */
1938 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1943 /*****
1944 * Get / Set FVF
1945 *****/
1946 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1949 /* Update the current state block */
1950 This->updateStateBlock->changed.fvf = TRUE;
1951 This->updateStateBlock->set.fvf = TRUE;
1953 if(This->updateStateBlock->fvf == fvf) {
1954 TRACE("Application is setting the old fvf over, nothing to do\n");
1955 return WINED3D_OK;
1958 This->updateStateBlock->fvf = fvf;
1959 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1961 return WINED3D_OK;
1965 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1967 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1968 *pfvf = This->stateBlock->fvf;
1969 return WINED3D_OK;
1972 /*****
1973 * Get / Set Stream Source
1974 *****/
1975 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1977 IWineD3DVertexBuffer *oldSrc;
1979 if (StreamNumber >= MAX_STREAMS) {
1980 WARN("Stream out of range %d\n", StreamNumber);
1981 return WINED3DERR_INVALIDCALL;
1984 oldSrc = This->stateBlock->streamSource[StreamNumber];
1985 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1987 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1988 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1990 if(oldSrc == pStreamData &&
1991 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1992 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1993 TRACE("Application is setting the old values over, nothing to do\n");
1994 return WINED3D_OK;
1997 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1998 if (pStreamData) {
1999 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2000 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2003 /* Handle recording of state blocks */
2004 if (This->isRecordingState) {
2005 TRACE("Recording... not performing anything\n");
2006 return WINED3D_OK;
2009 /* Need to do a getParent and pass the reffs up */
2010 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2011 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2012 so for now, just count internally */
2013 if (pStreamData != NULL) {
2014 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2015 InterlockedIncrement(&vbImpl->bindCount);
2017 if (oldSrc != NULL) {
2018 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2023 return WINED3D_OK;
2026 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2029 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2030 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2032 if (StreamNumber >= MAX_STREAMS) {
2033 WARN("Stream out of range %d\n", StreamNumber);
2034 return WINED3DERR_INVALIDCALL;
2036 *pStream = This->stateBlock->streamSource[StreamNumber];
2037 *pStride = This->stateBlock->streamStride[StreamNumber];
2038 if (pOffset) {
2039 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2042 if (*pStream != NULL) {
2043 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2045 return WINED3D_OK;
2048 /*Should be quite easy, just an extension of vertexdata
2049 ref...
2050 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2052 The divider is a bit odd though
2054 VertexOffset = StartVertex / Divider * StreamStride +
2055 VertexIndex / Divider * StreamStride + StreamOffset
2058 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2060 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2061 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2063 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2064 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2066 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2067 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2068 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2070 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2071 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2075 return WINED3D_OK;
2078 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2081 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2082 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2084 TRACE("(%p) : returning %d\n", This, *Divider);
2086 return WINED3D_OK;
2089 /*****
2090 * Get / Set & Multiply Transform
2091 *****/
2092 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2095 /* Most of this routine, comments included copied from ddraw tree initially: */
2096 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2098 /* Handle recording of state blocks */
2099 if (This->isRecordingState) {
2100 TRACE("Recording... not performing anything\n");
2101 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2102 This->updateStateBlock->set.transform[d3dts] = TRUE;
2103 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2104 return WINED3D_OK;
2108 * If the new matrix is the same as the current one,
2109 * we cut off any further processing. this seems to be a reasonable
2110 * optimization because as was noticed, some apps (warcraft3 for example)
2111 * tend towards setting the same matrix repeatedly for some reason.
2113 * From here on we assume that the new matrix is different, wherever it matters.
2115 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2116 TRACE("The app is setting the same matrix over again\n");
2117 return WINED3D_OK;
2118 } else {
2119 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2123 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2124 where ViewMat = Camera space, WorldMat = world space.
2126 In OpenGL, camera and world space is combined into GL_MODELVIEW
2127 matrix. The Projection matrix stay projection matrix.
2130 /* Capture the times we can just ignore the change for now */
2131 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2132 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2133 /* Handled by the state manager */
2136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2137 return WINED3D_OK;
2140 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2142 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2143 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2144 return WINED3D_OK;
2147 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2148 WINED3DMATRIX *mat = NULL;
2149 WINED3DMATRIX temp;
2151 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2152 * below means it will be recorded in a state block change, but it
2153 * works regardless where it is recorded.
2154 * If this is found to be wrong, change to StateBlock.
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2157 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2159 if (State < HIGHEST_TRANSFORMSTATE)
2161 mat = &This->updateStateBlock->transforms[State];
2162 } else {
2163 FIXME("Unhandled transform state!!\n");
2166 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2168 /* Apply change via set transform - will reapply to eg. lights this way */
2169 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2172 /*****
2173 * Get / Set Light
2174 *****/
2175 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2176 you can reference any indexes you want as long as that number max are enabled at any
2177 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2178 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2179 but when recording, just build a chain pretty much of commands to be replayed. */
2181 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2182 float rho;
2183 PLIGHTINFOEL *object = NULL;
2184 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2185 struct list *e;
2187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2188 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2190 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2191 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2192 if(object->OriginalIndex == Index) break;
2193 object = NULL;
2196 if(!object) {
2197 TRACE("Adding new light\n");
2198 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2199 if(!object) {
2200 ERR("Out of memory error when allocating a light\n");
2201 return E_OUTOFMEMORY;
2203 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2204 object->glIndex = -1;
2205 object->OriginalIndex = Index;
2206 object->changed = TRUE;
2209 /* Initialize the object */
2210 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,
2211 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2212 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2213 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2214 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2215 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2216 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2218 /* Save away the information */
2219 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2221 switch (pLight->Type) {
2222 case WINED3DLIGHT_POINT:
2223 /* Position */
2224 object->lightPosn[0] = pLight->Position.x;
2225 object->lightPosn[1] = pLight->Position.y;
2226 object->lightPosn[2] = pLight->Position.z;
2227 object->lightPosn[3] = 1.0f;
2228 object->cutoff = 180.0f;
2229 /* FIXME: Range */
2230 break;
2232 case WINED3DLIGHT_DIRECTIONAL:
2233 /* Direction */
2234 object->lightPosn[0] = -pLight->Direction.x;
2235 object->lightPosn[1] = -pLight->Direction.y;
2236 object->lightPosn[2] = -pLight->Direction.z;
2237 object->lightPosn[3] = 0.0;
2238 object->exponent = 0.0f;
2239 object->cutoff = 180.0f;
2240 break;
2242 case WINED3DLIGHT_SPOT:
2243 /* Position */
2244 object->lightPosn[0] = pLight->Position.x;
2245 object->lightPosn[1] = pLight->Position.y;
2246 object->lightPosn[2] = pLight->Position.z;
2247 object->lightPosn[3] = 1.0;
2249 /* Direction */
2250 object->lightDirn[0] = pLight->Direction.x;
2251 object->lightDirn[1] = pLight->Direction.y;
2252 object->lightDirn[2] = pLight->Direction.z;
2253 object->lightDirn[3] = 1.0;
2256 * opengl-ish and d3d-ish spot lights use too different models for the
2257 * light "intensity" as a function of the angle towards the main light direction,
2258 * so we only can approximate very roughly.
2259 * however spot lights are rather rarely used in games (if ever used at all).
2260 * furthermore if still used, probably nobody pays attention to such details.
2262 if (pLight->Falloff == 0) {
2263 rho = 6.28f;
2264 } else {
2265 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2267 if (rho < 0.0001) rho = 0.0001f;
2268 object->exponent = -0.3/log(cos(rho/2));
2269 if (object->exponent > 128.0) {
2270 object->exponent = 128.0;
2272 object->cutoff = pLight->Phi*90/M_PI;
2274 /* FIXME: Range */
2275 break;
2277 default:
2278 FIXME("Unrecognized light type %d\n", pLight->Type);
2281 /* Update the live definitions if the light is currently assigned a glIndex */
2282 if (object->glIndex != -1 && !This->isRecordingState) {
2283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2285 return WINED3D_OK;
2288 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2289 PLIGHTINFOEL *lightInfo = NULL;
2290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2291 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2292 struct list *e;
2293 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2295 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2296 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2297 if(lightInfo->OriginalIndex == Index) break;
2298 lightInfo = NULL;
2301 if (lightInfo == NULL) {
2302 TRACE("Light information requested but light not defined\n");
2303 return WINED3DERR_INVALIDCALL;
2306 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2307 return WINED3D_OK;
2310 /*****
2311 * Get / Set Light Enable
2312 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2313 *****/
2314 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2315 PLIGHTINFOEL *lightInfo = NULL;
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2317 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2318 struct list *e;
2319 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2321 /* Tests show true = 128...not clear why */
2322 Enable = Enable? 128: 0;
2324 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2325 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2326 if(lightInfo->OriginalIndex == Index) break;
2327 lightInfo = NULL;
2329 TRACE("Found light: %p\n", lightInfo);
2331 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2332 if (lightInfo == NULL) {
2334 TRACE("Light enabled requested but light not defined, so defining one!\n");
2335 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2337 /* Search for it again! Should be fairly quick as near head of list */
2338 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2339 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2340 if(lightInfo->OriginalIndex == Index) break;
2341 lightInfo = NULL;
2343 if (lightInfo == NULL) {
2344 FIXME("Adding default lights has failed dismally\n");
2345 return WINED3DERR_INVALIDCALL;
2349 lightInfo->enabledChanged = TRUE;
2350 if(!Enable) {
2351 if(lightInfo->glIndex != -1) {
2352 if(!This->isRecordingState) {
2353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2356 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2357 lightInfo->glIndex = -1;
2358 } else {
2359 TRACE("Light already disabled, nothing to do\n");
2361 } else {
2362 if (lightInfo->glIndex != -1) {
2363 /* nop */
2364 TRACE("Nothing to do as light was enabled\n");
2365 } else {
2366 int i;
2367 /* Find a free gl light */
2368 for(i = 0; i < This->maxConcurrentLights; i++) {
2369 if(This->stateBlock->activeLights[i] == NULL) {
2370 This->stateBlock->activeLights[i] = lightInfo;
2371 lightInfo->glIndex = i;
2372 break;
2375 if(lightInfo->glIndex == -1) {
2376 ERR("Too many concurrently active lights\n");
2377 return WINED3DERR_INVALIDCALL;
2380 /* i == lightInfo->glIndex */
2381 if(!This->isRecordingState) {
2382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2387 return WINED3D_OK;
2390 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2392 PLIGHTINFOEL *lightInfo = NULL;
2393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 struct list *e;
2395 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2396 TRACE("(%p) : for idx(%d)\n", This, Index);
2398 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2399 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2400 if(lightInfo->OriginalIndex == Index) break;
2401 lightInfo = NULL;
2404 if (lightInfo == NULL) {
2405 TRACE("Light enabled state requested but light not defined\n");
2406 return WINED3DERR_INVALIDCALL;
2408 /* true is 128 according to SetLightEnable */
2409 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2410 return WINED3D_OK;
2413 /*****
2414 * Get / Set Clip Planes
2415 *****/
2416 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2418 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2420 /* Validate Index */
2421 if (Index >= GL_LIMITS(clipplanes)) {
2422 TRACE("Application has requested clipplane this device doesn't support\n");
2423 return WINED3DERR_INVALIDCALL;
2426 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2427 This->updateStateBlock->set.clipplane[Index] = TRUE;
2428 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2429 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2430 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2431 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2433 /* Handle recording of state blocks */
2434 if (This->isRecordingState) {
2435 TRACE("Recording... not performing anything\n");
2436 return WINED3D_OK;
2439 /* Apply it */
2441 ENTER_GL();
2443 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2444 glMatrixMode(GL_MODELVIEW);
2445 glPushMatrix();
2446 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2448 TRACE("Clipplane [%f,%f,%f,%f]\n",
2449 This->updateStateBlock->clipplane[Index][0],
2450 This->updateStateBlock->clipplane[Index][1],
2451 This->updateStateBlock->clipplane[Index][2],
2452 This->updateStateBlock->clipplane[Index][3]);
2453 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2454 checkGLcall("glClipPlane");
2456 glPopMatrix();
2457 LEAVE_GL();
2459 return WINED3D_OK;
2462 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2464 TRACE("(%p) : for idx %d\n", This, Index);
2466 /* Validate Index */
2467 if (Index >= GL_LIMITS(clipplanes)) {
2468 TRACE("Application has requested clipplane this device doesn't support\n");
2469 return WINED3DERR_INVALIDCALL;
2472 pPlane[0] = This->stateBlock->clipplane[Index][0];
2473 pPlane[1] = This->stateBlock->clipplane[Index][1];
2474 pPlane[2] = This->stateBlock->clipplane[Index][2];
2475 pPlane[3] = This->stateBlock->clipplane[Index][3];
2476 return WINED3D_OK;
2479 /*****
2480 * Get / Set Clip Plane Status
2481 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2482 *****/
2483 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2485 FIXME("(%p) : stub\n", This);
2486 if (NULL == pClipStatus) {
2487 return WINED3DERR_INVALIDCALL;
2489 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2490 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2491 return WINED3D_OK;
2494 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2496 FIXME("(%p) : stub\n", This);
2497 if (NULL == pClipStatus) {
2498 return WINED3DERR_INVALIDCALL;
2500 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2501 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2502 return WINED3D_OK;
2505 /*****
2506 * Get / Set Material
2507 *****/
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 This->updateStateBlock->changed.material = TRUE;
2512 This->updateStateBlock->set.material = TRUE;
2513 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2515 /* Handle recording of state blocks */
2516 if (This->isRecordingState) {
2517 TRACE("Recording... not performing anything\n");
2518 return WINED3D_OK;
2521 ENTER_GL();
2522 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2523 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2524 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2525 pMaterial->Ambient.b, pMaterial->Ambient.a);
2526 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2527 pMaterial->Specular.b, pMaterial->Specular.a);
2528 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2529 pMaterial->Emissive.b, pMaterial->Emissive.a);
2530 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2532 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2533 checkGLcall("glMaterialfv(GL_AMBIENT)");
2534 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2535 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2537 /* Only change material color if specular is enabled, otherwise it is set to black */
2538 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2539 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2540 checkGLcall("glMaterialfv(GL_SPECULAR");
2541 } else {
2542 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2543 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2544 checkGLcall("glMaterialfv(GL_SPECULAR");
2546 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2547 checkGLcall("glMaterialfv(GL_EMISSION)");
2548 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2549 checkGLcall("glMaterialf(GL_SHININESS");
2551 LEAVE_GL();
2552 return WINED3D_OK;
2555 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2558 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2559 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2560 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2561 pMaterial->Ambient.b, pMaterial->Ambient.a);
2562 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2563 pMaterial->Specular.b, pMaterial->Specular.a);
2564 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2565 pMaterial->Emissive.b, pMaterial->Emissive.a);
2566 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2568 return WINED3D_OK;
2571 /*****
2572 * Get / Set Indices
2573 *****/
2574 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2575 UINT BaseVertexIndex) {
2576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2577 IWineD3DIndexBuffer *oldIdxs;
2578 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2580 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2581 oldIdxs = This->updateStateBlock->pIndexData;
2583 This->updateStateBlock->changed.indices = TRUE;
2584 This->updateStateBlock->set.indices = TRUE;
2585 This->updateStateBlock->pIndexData = pIndexData;
2586 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2588 /* Handle recording of state blocks */
2589 if (This->isRecordingState) {
2590 TRACE("Recording... not performing anything\n");
2591 return WINED3D_OK;
2594 /* So far only the base vertex index is tracked */
2595 if(BaseVertexIndex != oldBaseIndex) {
2596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2598 return WINED3D_OK;
2601 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 *ppIndexData = This->stateBlock->pIndexData;
2606 /* up ref count on ppindexdata */
2607 if (*ppIndexData) {
2608 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2609 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2610 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2611 }else{
2612 TRACE("(%p) No index data set\n", This);
2614 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2616 return WINED3D_OK;
2619 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2620 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2622 TRACE("(%p)->(%d)\n", This, BaseIndex);
2624 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2625 TRACE("Application is setting the old value over, nothing to do\n");
2626 return WINED3D_OK;
2629 This->updateStateBlock->baseVertexIndex = BaseIndex;
2631 if (This->isRecordingState) {
2632 TRACE("Recording... not performing anything\n");
2633 return WINED3D_OK;
2635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2636 return WINED3D_OK;
2639 /*****
2640 * Get / Set Viewports
2641 *****/
2642 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 TRACE("(%p)\n", This);
2646 This->updateStateBlock->changed.viewport = TRUE;
2647 This->updateStateBlock->set.viewport = TRUE;
2648 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2650 /* Handle recording of state blocks */
2651 if (This->isRecordingState) {
2652 TRACE("Recording... not performing anything\n");
2653 return WINED3D_OK;
2656 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2657 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2660 return WINED3D_OK;
2664 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 TRACE("(%p)\n", This);
2667 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2668 return WINED3D_OK;
2671 /*****
2672 * Get / Set Render States
2673 * TODO: Verify against dx9 definitions
2674 *****/
2675 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 DWORD oldValue = This->stateBlock->renderState[State];
2680 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2682 This->updateStateBlock->changed.renderState[State] = TRUE;
2683 This->updateStateBlock->set.renderState[State] = TRUE;
2684 This->updateStateBlock->renderState[State] = Value;
2686 /* Handle recording of state blocks */
2687 if (This->isRecordingState) {
2688 TRACE("Recording... not performing anything\n");
2689 return WINED3D_OK;
2692 /* Compared here and not before the assignment to allow proper stateblock recording */
2693 if(Value == oldValue) {
2694 TRACE("Application is setting the old value over, nothing to do\n");
2695 } else {
2696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2699 return WINED3D_OK;
2702 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2704 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2705 *pValue = This->stateBlock->renderState[State];
2706 return WINED3D_OK;
2709 /*****
2710 * Get / Set Sampler States
2711 * TODO: Verify against dx9 definitions
2712 *****/
2714 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2716 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2719 * SetSampler is designed to allow for more than the standard up to 8 textures
2720 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2721 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2723 * http://developer.nvidia.com/object/General_FAQ.html#t6
2725 * There are two new settings for GForce
2726 * the sampler one:
2727 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2728 * and the texture one:
2729 * GL_MAX_TEXTURE_COORDS_ARB.
2730 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2731 ******************/
2732 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2733 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
2734 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2735 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
2736 return WINED3DERR_INVALIDCALL;
2739 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2740 debug_d3dsamplerstate(Type), Type, Value);
2741 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2742 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2743 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2745 /* Handle recording of state blocks */
2746 if (This->isRecordingState) {
2747 TRACE("Recording... not performing anything\n");
2748 return WINED3D_OK;
2751 if(oldValue == Value) {
2752 TRACE("Application is setting the old value over, nothing to do\n");
2753 return WINED3D_OK;
2756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2758 return WINED3D_OK;
2761 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2763 /** TODO: check that sampler is in range **/
2764 *Value = This->stateBlock->samplerState[Sampler][Type];
2765 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2767 return WINED3D_OK;
2770 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 RECT windowRect;
2773 UINT winHeight;
2775 This->updateStateBlock->set.scissorRect = TRUE;
2776 This->updateStateBlock->changed.scissorRect = TRUE;
2777 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2779 if(This->isRecordingState) {
2780 TRACE("Recording... not performing anything\n");
2781 return WINED3D_OK;
2784 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
2785 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2786 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2788 winHeight = windowRect.bottom - windowRect.top;
2789 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
2790 pRect->right - pRect->left, pRect->bottom - pRect->top);
2791 ENTER_GL();
2792 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
2793 checkGLcall("glScissor");
2794 LEAVE_GL();
2796 return WINED3D_OK;
2799 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2803 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2804 return WINED3D_OK;
2807 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2809 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2811 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2813 This->updateStateBlock->vertexDecl = pDecl;
2814 This->updateStateBlock->changed.vertexDecl = TRUE;
2815 This->updateStateBlock->set.vertexDecl = TRUE;
2817 if (This->isRecordingState) {
2818 TRACE("Recording... not performing anything\n");
2819 return WINED3D_OK;
2820 } else if(pDecl == oldDecl) {
2821 /* Checked after the assignment to allow proper stateblock recording */
2822 TRACE("Application is setting the old declaration over, nothing to do\n");
2823 return WINED3D_OK;
2826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2827 return WINED3D_OK;
2830 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2835 *ppDecl = This->stateBlock->vertexDecl;
2836 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2837 return WINED3D_OK;
2840 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2842 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2844 This->updateStateBlock->vertexShader = pShader;
2845 This->updateStateBlock->changed.vertexShader = TRUE;
2846 This->updateStateBlock->set.vertexShader = TRUE;
2848 if (This->isRecordingState) {
2849 TRACE("Recording... not performing anything\n");
2850 return WINED3D_OK;
2851 } else if(oldShader == pShader) {
2852 /* Checked here to allow proper stateblock recording */
2853 TRACE("App is setting the old shader over, nothing to do\n");
2854 return WINED3D_OK;
2857 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2861 return WINED3D_OK;
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2867 if (NULL == ppShader) {
2868 return WINED3DERR_INVALIDCALL;
2870 *ppShader = This->stateBlock->vertexShader;
2871 if( NULL != *ppShader)
2872 IWineD3DVertexShader_AddRef(*ppShader);
2874 TRACE("(%p) : returning %p\n", This, *ppShader);
2875 return WINED3D_OK;
2878 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2879 IWineD3DDevice *iface,
2880 UINT start,
2881 CONST BOOL *srcData,
2882 UINT count) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2885 int i, cnt = min(count, MAX_CONST_B - start);
2887 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2888 iface, srcData, start, count);
2890 if (srcData == NULL || cnt < 0)
2891 return WINED3DERR_INVALIDCALL;
2893 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2894 for (i = 0; i < cnt; i++)
2895 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2897 for (i = start; i < cnt + start; ++i) {
2898 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2899 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2904 return WINED3D_OK;
2907 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2908 IWineD3DDevice *iface,
2909 UINT start,
2910 BOOL *dstData,
2911 UINT count) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 int cnt = min(count, MAX_CONST_B - start);
2916 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2917 iface, dstData, start, count);
2919 if (dstData == NULL || cnt < 0)
2920 return WINED3DERR_INVALIDCALL;
2922 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2923 return WINED3D_OK;
2926 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2927 IWineD3DDevice *iface,
2928 UINT start,
2929 CONST int *srcData,
2930 UINT count) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2933 int i, cnt = min(count, MAX_CONST_I - start);
2935 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2936 iface, srcData, start, count);
2938 if (srcData == NULL || cnt < 0)
2939 return WINED3DERR_INVALIDCALL;
2941 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2942 for (i = 0; i < cnt; i++)
2943 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2944 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2946 for (i = start; i < cnt + start; ++i) {
2947 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2948 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2953 return WINED3D_OK;
2956 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2957 IWineD3DDevice *iface,
2958 UINT start,
2959 int *dstData,
2960 UINT count) {
2962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2963 int cnt = min(count, MAX_CONST_I - start);
2965 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2966 iface, dstData, start, count);
2968 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2969 return WINED3DERR_INVALIDCALL;
2971 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2972 return WINED3D_OK;
2975 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2976 IWineD3DDevice *iface,
2977 UINT start,
2978 CONST float *srcData,
2979 UINT count) {
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2984 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2985 iface, srcData, start, count);
2987 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
2988 return WINED3DERR_INVALIDCALL;
2990 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
2991 for (i = 0; i < cnt; i++)
2992 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2993 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2995 for (i = start; i < cnt + start; ++i) {
2996 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
2997 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
2998 ptr->idx = i;
2999 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3000 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3002 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3007 return WINED3D_OK;
3010 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3011 IWineD3DDevice *iface,
3012 UINT start,
3013 float *dstData,
3014 UINT count) {
3016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3019 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3020 iface, dstData, start, count);
3022 if (dstData == NULL || cnt < 0)
3023 return WINED3DERR_INVALIDCALL;
3025 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3026 return WINED3D_OK;
3029 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3030 DWORD i;
3031 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3036 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3037 DWORD i, tex;
3038 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3039 * it is never called.
3041 * Rules are:
3042 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3043 * that would be really messy and require shader recompilation
3044 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3045 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3046 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3047 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3049 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3050 if(This->oneToOneTexUnitMap) {
3051 TRACE("Not touching 1:1 map\n");
3052 return;
3054 TRACE("Restoring 1:1 texture unit mapping\n");
3055 /* Restore a 1:1 mapping */
3056 for(i = 0; i < MAX_SAMPLERS; i++) {
3057 if(This->texUnitMap[i] != i) {
3058 This->texUnitMap[i] = i;
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3060 markTextureStagesDirty(This, i);
3063 This->oneToOneTexUnitMap = TRUE;
3064 return;
3065 } else {
3066 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3067 * First, see if we can succeed at all
3069 tex = 0;
3070 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3071 if(This->stateBlock->textures[i] == NULL) tex++;
3074 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3075 FIXME("Too many bound textures to support the combiner settings\n");
3076 return;
3079 /* Now work out the mapping */
3080 tex = 0;
3081 This->oneToOneTexUnitMap = FALSE;
3082 WARN("Non 1:1 mapping UNTESTED!\n");
3083 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3084 /* Skip NULL textures */
3085 if (!This->stateBlock->textures[i]) {
3086 /* Map to -1, so the check below doesn't fail if a non-NULL
3087 * texture is set on this stage */
3088 TRACE("Mapping texture stage %d to -1\n", i);
3089 This->texUnitMap[i] = -1;
3091 continue;
3094 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3095 if(This->texUnitMap[i] != tex) {
3096 This->texUnitMap[i] = tex;
3097 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3098 markTextureStagesDirty(This, i);
3101 ++tex;
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3109 This->updateStateBlock->pixelShader = pShader;
3110 This->updateStateBlock->changed.pixelShader = TRUE;
3111 This->updateStateBlock->set.pixelShader = TRUE;
3113 /* Handle recording of state blocks */
3114 if (This->isRecordingState) {
3115 TRACE("Recording... not performing anything\n");
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3120 return WINED3D_OK;
3123 if(pShader == oldShader) {
3124 TRACE("App is setting the old pixel shader over, nothing to do\n");
3125 return WINED3D_OK;
3128 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3131 /* Rebuild the texture unit mapping if nvrc's are supported */
3132 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3133 IWineD3DDeviceImpl_FindTexUnitMap(This);
3136 return WINED3D_OK;
3139 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 if (NULL == ppShader) {
3143 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3144 return WINED3DERR_INVALIDCALL;
3147 *ppShader = This->stateBlock->pixelShader;
3148 if (NULL != *ppShader) {
3149 IWineD3DPixelShader_AddRef(*ppShader);
3151 TRACE("(%p) : returning %p\n", This, *ppShader);
3152 return WINED3D_OK;
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3156 IWineD3DDevice *iface,
3157 UINT start,
3158 CONST BOOL *srcData,
3159 UINT count) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 int i, cnt = min(count, MAX_CONST_B - start);
3164 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3165 iface, srcData, start, count);
3167 if (srcData == NULL || cnt < 0)
3168 return WINED3DERR_INVALIDCALL;
3170 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3171 for (i = 0; i < cnt; i++)
3172 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3174 for (i = start; i < cnt + start; ++i) {
3175 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3176 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3179 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3181 return WINED3D_OK;
3184 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3185 IWineD3DDevice *iface,
3186 UINT start,
3187 BOOL *dstData,
3188 UINT count) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 int cnt = min(count, MAX_CONST_B - start);
3193 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3194 iface, dstData, start, count);
3196 if (dstData == NULL || cnt < 0)
3197 return WINED3DERR_INVALIDCALL;
3199 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3200 return WINED3D_OK;
3203 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3204 IWineD3DDevice *iface,
3205 UINT start,
3206 CONST int *srcData,
3207 UINT count) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 int i, cnt = min(count, MAX_CONST_I - start);
3212 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3213 iface, srcData, start, count);
3215 if (srcData == NULL || cnt < 0)
3216 return WINED3DERR_INVALIDCALL;
3218 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3219 for (i = 0; i < cnt; i++)
3220 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3221 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3223 for (i = start; i < cnt + start; ++i) {
3224 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3225 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3230 return WINED3D_OK;
3233 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3234 IWineD3DDevice *iface,
3235 UINT start,
3236 int *dstData,
3237 UINT count) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 int cnt = min(count, MAX_CONST_I - start);
3242 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3243 iface, dstData, start, count);
3245 if (dstData == NULL || cnt < 0)
3246 return WINED3DERR_INVALIDCALL;
3248 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3249 return WINED3D_OK;
3252 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3253 IWineD3DDevice *iface,
3254 UINT start,
3255 CONST float *srcData,
3256 UINT count) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3261 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3262 iface, srcData, start, count);
3264 if (srcData == NULL || cnt < 0)
3265 return WINED3DERR_INVALIDCALL;
3267 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3268 for (i = 0; i < cnt; i++)
3269 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3270 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3272 for (i = start; i < cnt + start; ++i) {
3273 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3274 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3275 ptr->idx = i;
3276 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3277 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3279 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3284 return WINED3D_OK;
3287 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3288 IWineD3DDevice *iface,
3289 UINT start,
3290 float *dstData,
3291 UINT count) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3296 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3297 iface, dstData, start, count);
3299 if (dstData == NULL || cnt < 0)
3300 return WINED3DERR_INVALIDCALL;
3302 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3303 return WINED3D_OK;
3306 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3307 static HRESULT
3308 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3309 char *dest_ptr, *dest_conv = NULL;
3310 unsigned int i;
3311 DWORD DestFVF = dest->fvf;
3312 WINED3DVIEWPORT vp;
3313 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3314 BOOL doClip;
3315 int numTextures;
3317 if (SrcFVF & WINED3DFVF_NORMAL) {
3318 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3321 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3322 ERR("Source has no position mask\n");
3323 return WINED3DERR_INVALIDCALL;
3326 /* We might access VBOs from this code, so hold the lock */
3327 ENTER_GL();
3329 if (dest->resource.allocatedMemory == NULL) {
3330 /* This may happen if we do direct locking into a vbo. Unlikely,
3331 * but theoretically possible(ddraw processvertices test)
3333 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3334 if(!dest->resource.allocatedMemory) {
3335 LEAVE_GL();
3336 ERR("Out of memory\n");
3337 return E_OUTOFMEMORY;
3339 if(dest->vbo) {
3340 void *src;
3341 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3342 checkGLcall("glBindBufferARB");
3343 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3344 if(src) {
3345 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3347 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3348 checkGLcall("glUnmapBufferARB");
3352 /* Get a pointer into the destination vbo(create one if none exists) and
3353 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3355 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3356 CreateVBO(dest);
3359 if(dest->vbo) {
3360 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3361 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3362 if(!dest_conv) {
3363 ERR("glMapBuffer failed\n");
3364 /* Continue without storing converted vertices */
3368 /* Should I clip?
3369 * a) WINED3DRS_CLIPPING is enabled
3370 * b) WINED3DVOP_CLIP is passed
3372 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3373 static BOOL warned = FALSE;
3375 * The clipping code is not quite correct. Some things need
3376 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3377 * so disable clipping for now.
3378 * (The graphics in Half-Life are broken, and my processvertices
3379 * test crashes with IDirect3DDevice3)
3380 doClip = TRUE;
3382 doClip = FALSE;
3383 if(!warned) {
3384 warned = TRUE;
3385 FIXME("Clipping is broken and disabled for now\n");
3387 } else doClip = FALSE;
3388 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3389 if(dest_conv) {
3390 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3393 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3394 WINED3DTS_VIEW,
3395 &view_mat);
3396 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3397 WINED3DTS_PROJECTION,
3398 &proj_mat);
3399 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3400 WINED3DTS_WORLDMATRIX(0),
3401 &world_mat);
3403 TRACE("View mat:\n");
3404 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);
3405 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);
3406 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);
3407 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);
3409 TRACE("Proj mat:\n");
3410 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);
3411 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);
3412 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);
3413 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);
3415 TRACE("World mat:\n");
3416 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);
3417 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);
3418 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);
3419 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);
3421 /* Get the viewport */
3422 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3423 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3424 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3426 multiply_matrix(&mat,&view_mat,&world_mat);
3427 multiply_matrix(&mat,&proj_mat,&mat);
3429 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3431 for (i = 0; i < dwCount; i+= 1) {
3432 unsigned int tex_index;
3434 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3435 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3436 /* The position first */
3437 float *p =
3438 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3439 float x, y, z, rhw;
3440 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3442 /* Multiplication with world, view and projection matrix */
3443 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);
3444 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);
3445 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);
3446 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);
3448 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3450 /* WARNING: The following things are taken from d3d7 and were not yet checked
3451 * against d3d8 or d3d9!
3454 /* Clipping conditions: From
3455 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3457 * A vertex is clipped if it does not match the following requirements
3458 * -rhw < x <= rhw
3459 * -rhw < y <= rhw
3460 * 0 < z <= rhw
3461 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3463 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3464 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3468 if( !doClip ||
3469 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3470 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3471 ( rhw > eps ) ) ) {
3473 /* "Normal" viewport transformation (not clipped)
3474 * 1) The values are divided by rhw
3475 * 2) The y axis is negative, so multiply it with -1
3476 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3477 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3478 * 4) Multiply x with Width/2 and add Width/2
3479 * 5) The same for the height
3480 * 6) Add the viewpoint X and Y to the 2D coordinates and
3481 * The minimum Z value to z
3482 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3484 * Well, basically it's simply a linear transformation into viewport
3485 * coordinates
3488 x /= rhw;
3489 y /= rhw;
3490 z /= rhw;
3492 y *= -1;
3494 x *= vp.Width / 2;
3495 y *= vp.Height / 2;
3496 z *= vp.MaxZ - vp.MinZ;
3498 x += vp.Width / 2 + vp.X;
3499 y += vp.Height / 2 + vp.Y;
3500 z += vp.MinZ;
3502 rhw = 1 / rhw;
3503 } else {
3504 /* That vertex got clipped
3505 * Contrary to OpenGL it is not dropped completely, it just
3506 * undergoes a different calculation.
3508 TRACE("Vertex got clipped\n");
3509 x += rhw;
3510 y += rhw;
3512 x /= 2;
3513 y /= 2;
3515 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3516 * outside of the main vertex buffer memory. That needs some more
3517 * investigation...
3521 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3524 ( (float *) dest_ptr)[0] = x;
3525 ( (float *) dest_ptr)[1] = y;
3526 ( (float *) dest_ptr)[2] = z;
3527 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3529 dest_ptr += 3 * sizeof(float);
3531 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3532 dest_ptr += sizeof(float);
3535 if(dest_conv) {
3536 float w = 1 / rhw;
3537 ( (float *) dest_conv)[0] = x * w;
3538 ( (float *) dest_conv)[1] = y * w;
3539 ( (float *) dest_conv)[2] = z * w;
3540 ( (float *) dest_conv)[3] = w;
3542 dest_conv += 3 * sizeof(float);
3544 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3545 dest_conv += sizeof(float);
3549 if (DestFVF & WINED3DFVF_PSIZE) {
3550 dest_ptr += sizeof(DWORD);
3551 if(dest_conv) dest_conv += sizeof(DWORD);
3553 if (DestFVF & WINED3DFVF_NORMAL) {
3554 float *normal =
3555 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3556 /* AFAIK this should go into the lighting information */
3557 FIXME("Didn't expect the destination to have a normal\n");
3558 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3559 if(dest_conv) {
3560 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3564 if (DestFVF & WINED3DFVF_DIFFUSE) {
3565 DWORD *color_d =
3566 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3567 if(!color_d) {
3568 static BOOL warned = FALSE;
3570 if(!warned) {
3571 ERR("No diffuse color in source, but destination has one\n");
3572 warned = TRUE;
3575 *( (DWORD *) dest_ptr) = 0xffffffff;
3576 dest_ptr += sizeof(DWORD);
3578 if(dest_conv) {
3579 *( (DWORD *) dest_conv) = 0xffffffff;
3580 dest_conv += sizeof(DWORD);
3583 else {
3584 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3585 if(dest_conv) {
3586 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3587 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3588 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3589 dest_conv += sizeof(DWORD);
3594 if (DestFVF & WINED3DFVF_SPECULAR) {
3595 /* What's the color value in the feedback buffer? */
3596 DWORD *color_s =
3597 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3598 if(!color_s) {
3599 static BOOL warned = FALSE;
3601 if(!warned) {
3602 ERR("No specular color in source, but destination has one\n");
3603 warned = TRUE;
3606 *( (DWORD *) dest_ptr) = 0xFF000000;
3607 dest_ptr += sizeof(DWORD);
3609 if(dest_conv) {
3610 *( (DWORD *) dest_conv) = 0xFF000000;
3611 dest_conv += sizeof(DWORD);
3614 else {
3615 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3616 if(dest_conv) {
3617 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3618 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3619 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3620 dest_conv += sizeof(DWORD);
3625 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3626 float *tex_coord =
3627 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3628 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3629 if(!tex_coord) {
3630 ERR("No source texture, but destination requests one\n");
3631 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3632 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3634 else {
3635 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3636 if(dest_conv) {
3637 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3643 if(dest_conv) {
3644 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3645 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3648 LEAVE_GL();
3650 return WINED3D_OK;
3652 #undef copy_and_next
3654 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3656 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3657 WineDirect3DVertexStridedData strided;
3658 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3660 if (!SrcImpl) {
3661 WARN("NULL source vertex buffer\n");
3662 return WINED3DERR_INVALIDCALL;
3664 /* We don't need the source vbo because this buffer is only used as
3665 * a source for ProcessVertices. Avoid wasting resources by converting the
3666 * buffer and loading the VBO
3668 if(SrcImpl->vbo) {
3669 TRACE("Releasing the source vbo, it won't be needed\n");
3671 if(!SrcImpl->resource.allocatedMemory) {
3672 /* Rescue the data from the buffer */
3673 void *src;
3674 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3675 if(!SrcImpl->resource.allocatedMemory) {
3676 ERR("Out of memory\n");
3677 return E_OUTOFMEMORY;
3680 ENTER_GL();
3681 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3682 checkGLcall("glBindBufferARB");
3684 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3685 if(src) {
3686 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3689 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3690 checkGLcall("glUnmapBufferARB");
3691 } else {
3692 ENTER_GL();
3695 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3696 checkGLcall("glBindBufferARB");
3697 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3698 checkGLcall("glDeleteBuffersARB");
3699 LEAVE_GL();
3701 SrcImpl->vbo = 0;
3704 memset(&strided, 0, sizeof(strided));
3705 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3707 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3710 /*****
3711 * Get / Set Texture Stage States
3712 * TODO: Verify against dx9 definitions
3713 *****/
3714 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3716 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3718 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3720 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3722 /* Reject invalid texture units */
3723 if (Stage >= GL_LIMITS(texture_stages)) {
3724 TRACE("Attempt to access invalid texture rejected\n");
3725 return WINED3DERR_INVALIDCALL;
3728 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3729 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3730 This->updateStateBlock->textureState[Stage][Type] = Value;
3732 if (This->isRecordingState) {
3733 TRACE("Recording... not performing anything\n");
3734 return WINED3D_OK;
3737 /* Checked after the assignments to allow proper stateblock recording */
3738 if(oldValue == Value) {
3739 TRACE("App is setting the old value over, nothing to do\n");
3740 return WINED3D_OK;
3743 if(Stage > This->stateBlock->lowest_disabled_stage &&
3744 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3745 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3746 * Changes in other states are important on disabled stages too
3748 return WINED3D_OK;
3751 if(Type == WINED3DTSS_COLOROP) {
3752 int i;
3754 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3755 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3756 * they have to be disabled
3758 * The current stage is dirtified below.
3760 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3761 TRACE("Additionally dirtifying stage %d\n", i);
3762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3764 This->stateBlock->lowest_disabled_stage = Stage;
3765 TRACE("New lowest disabled: %d\n", Stage);
3766 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3767 /* Previously disabled stage enabled. Stages above it may need enabling
3768 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3769 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3771 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3774 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3775 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3776 break;
3778 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3781 This->stateBlock->lowest_disabled_stage = i;
3782 TRACE("New lowest disabled: %d\n", i);
3784 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3785 /* TODO: Built a stage -> texture unit mapping for register combiners */
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3791 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3792 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3793 * will call FindTexUnitMap too.
3795 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3796 IWineD3DDeviceImpl_FindTexUnitMap(This);
3798 return WINED3D_OK;
3801 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3803 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3804 *pValue = This->updateStateBlock->textureState[Stage][Type];
3805 return WINED3D_OK;
3808 /*****
3809 * Get / Set Texture
3810 *****/
3811 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3814 IWineD3DBaseTexture *oldTexture;
3816 oldTexture = This->updateStateBlock->textures[Stage];
3817 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3819 #if 0 /* TODO: check so vertex textures */
3820 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3821 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3822 return WINED3D_OK;
3824 #endif
3826 /* Reject invalid texture units */
3827 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
3828 WARN("Attempt to access invalid texture rejected\n");
3829 return WINED3DERR_INVALIDCALL;
3832 if(pTexture != NULL) {
3833 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3835 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3836 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3837 return WINED3DERR_INVALIDCALL;
3839 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3842 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3843 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3845 This->updateStateBlock->set.textures[Stage] = TRUE;
3846 This->updateStateBlock->changed.textures[Stage] = TRUE;
3847 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3848 This->updateStateBlock->textures[Stage] = pTexture;
3850 /* Handle recording of state blocks */
3851 if (This->isRecordingState) {
3852 TRACE("Recording... not performing anything\n");
3853 return WINED3D_OK;
3856 if(oldTexture == pTexture) {
3857 TRACE("App is setting the same texture again, nothing to do\n");
3858 return WINED3D_OK;
3861 /** NOTE: MSDN says that setTexture increases the reference count,
3862 * and the the application nust set the texture back to null (or have a leaky application),
3863 * This means we should pass the refcount up to the parent
3864 *******************************/
3865 if (NULL != This->updateStateBlock->textures[Stage]) {
3866 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3867 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3869 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3870 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3871 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3872 * so the COLOROP and ALPHAOP have to be dirtified.
3874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3877 if(bindCount == 1) {
3878 new->baseTexture.sampler = Stage;
3880 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3884 if (NULL != oldTexture) {
3885 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3886 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3888 IWineD3DBaseTexture_Release(oldTexture);
3889 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3894 if(bindCount && old->baseTexture.sampler == Stage) {
3895 int i;
3896 /* Have to do a search for the other sampler(s) where the texture is bound to
3897 * Shouldn't happen as long as apps bind a texture only to one stage
3899 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3900 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3901 if(This->updateStateBlock->textures[i] == oldTexture) {
3902 old->baseTexture.sampler = i;
3903 break;
3909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3911 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3912 * pixel shader is used
3914 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3915 IWineD3DDeviceImpl_FindTexUnitMap(This);
3918 return WINED3D_OK;
3921 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3923 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3925 /* Reject invalid texture units */
3926 if (Stage >= GL_LIMITS(sampler_stages)) {
3927 TRACE("Attempt to access invalid texture rejected\n");
3928 return WINED3DERR_INVALIDCALL;
3930 *ppTexture=This->stateBlock->textures[Stage];
3931 if (*ppTexture)
3932 IWineD3DBaseTexture_AddRef(*ppTexture);
3934 return WINED3D_OK;
3937 /*****
3938 * Get Back Buffer
3939 *****/
3940 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3941 IWineD3DSurface **ppBackBuffer) {
3942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 IWineD3DSwapChain *swapChain;
3944 HRESULT hr;
3946 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3948 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3949 if (hr == WINED3D_OK) {
3950 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3951 IWineD3DSwapChain_Release(swapChain);
3952 } else {
3953 *ppBackBuffer = NULL;
3955 return hr;
3958 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3960 WARN("(%p) : stub, calling idirect3d for now\n", This);
3961 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3964 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3966 IWineD3DSwapChain *swapChain;
3967 HRESULT hr;
3969 if(iSwapChain > 0) {
3970 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3971 if (hr == WINED3D_OK) {
3972 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3973 IWineD3DSwapChain_Release(swapChain);
3974 } else {
3975 FIXME("(%p) Error getting display mode\n", This);
3977 } else {
3978 /* Don't read the real display mode,
3979 but return the stored mode instead. X11 can't change the color
3980 depth, and some apps are pretty angry if they SetDisplayMode from
3981 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3983 Also don't relay to the swapchain because with ddraw it's possible
3984 that there isn't a swapchain at all */
3985 pMode->Width = This->ddraw_width;
3986 pMode->Height = This->ddraw_height;
3987 pMode->Format = This->ddraw_format;
3988 pMode->RefreshRate = 0;
3989 hr = WINED3D_OK;
3992 return hr;
3995 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3997 TRACE("(%p)->(%p)\n", This, hWnd);
3999 if(This->ddraw_fullscreen) {
4000 if(This->ddraw_window && This->ddraw_window != hWnd) {
4001 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4003 if(hWnd && This->ddraw_window != hWnd) {
4004 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4008 This->ddraw_window = hWnd;
4009 return WINED3D_OK;
4012 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4014 TRACE("(%p)->(%p)\n", This, hWnd);
4016 *hWnd = This->ddraw_window;
4017 return WINED3D_OK;
4020 /*****
4021 * Stateblock related functions
4022 *****/
4024 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4026 IWineD3DStateBlockImpl *object;
4027 HRESULT temp_result;
4028 int i;
4030 TRACE("(%p)\n", This);
4032 if (This->isRecordingState) {
4033 return WINED3DERR_INVALIDCALL;
4036 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4037 if (NULL == object ) {
4038 FIXME("(%p)Error allocating memory for stateblock\n", This);
4039 return E_OUTOFMEMORY;
4041 TRACE("(%p) created object %p\n", This, object);
4042 object->wineD3DDevice= This;
4043 /** FIXME: object->parent = parent; **/
4044 object->parent = NULL;
4045 object->blockType = WINED3DSBT_ALL;
4046 object->ref = 1;
4047 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4049 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4050 list_init(&object->lightMap[i]);
4053 temp_result = allocate_shader_constants(object);
4054 if (WINED3D_OK != temp_result)
4055 return temp_result;
4057 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4058 This->updateStateBlock = object;
4059 This->isRecordingState = TRUE;
4061 TRACE("(%p) recording stateblock %p\n",This , object);
4062 return WINED3D_OK;
4065 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4068 if (!This->isRecordingState) {
4069 FIXME("(%p) not recording! returning error\n", This);
4070 *ppStateBlock = NULL;
4071 return WINED3DERR_INVALIDCALL;
4074 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4075 This->isRecordingState = FALSE;
4076 This->updateStateBlock = This->stateBlock;
4077 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4078 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4079 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4080 return WINED3D_OK;
4083 /*****
4084 * Scene related functions
4085 *****/
4086 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4087 /* At the moment we have no need for any functionality at the beginning
4088 of a scene */
4089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4090 TRACE("(%p)\n", This);
4092 if(This->inScene) {
4093 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4094 return WINED3DERR_INVALIDCALL;
4096 This->inScene = TRUE;
4097 return WINED3D_OK;
4100 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4102 TRACE("(%p)\n", This);
4104 if(!This->inScene) {
4105 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4106 return WINED3DERR_INVALIDCALL;
4109 ENTER_GL();
4110 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4111 glFlush();
4112 checkGLcall("glFlush");
4113 LEAVE_GL();
4115 This->inScene = FALSE;
4116 return WINED3D_OK;
4119 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4120 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4121 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4123 IWineD3DSwapChain *swapChain = NULL;
4124 int i;
4125 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4127 TRACE("(%p) Presenting the frame\n", This);
4129 for(i = 0 ; i < swapchains ; i ++) {
4131 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4132 TRACE("presentinng chain %d, %p\n", i, swapChain);
4133 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4134 IWineD3DSwapChain_Release(swapChain);
4137 return WINED3D_OK;
4140 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4141 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4144 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4145 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4146 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4147 GLbitfield glMask = 0;
4148 GLboolean old_ztest;
4149 GLfloat old_z_clear_value;
4150 GLint old_stencil_clear_value;
4151 GLfloat old_color_clear_value[4];
4152 unsigned int i;
4153 CONST WINED3DRECT* curRect;
4155 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4156 Count, pRects, Flags, Z, Stencil);
4158 ENTER_GL();
4160 glEnable(GL_SCISSOR_TEST);
4161 checkGLcall("glEnable GL_SCISSOR_TEST");
4163 if (Count > 0 && pRects) {
4164 curRect = pRects;
4165 } else {
4166 curRect = NULL;
4169 /* Only set the values up once, as they are not changing */
4170 if (Flags & WINED3DCLEAR_STENCIL) {
4171 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4172 glClearStencil(Stencil);
4173 checkGLcall("glClearStencil");
4174 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4175 glStencilMask(0xFFFFFFFF);
4178 if (Flags & WINED3DCLEAR_ZBUFFER) {
4179 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4180 glDepthMask(GL_TRUE);
4181 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4182 glClearDepth(Z);
4183 checkGLcall("glClearDepth");
4184 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4187 if (Flags & WINED3DCLEAR_TARGET) {
4188 TRACE("Clearing screen with glClear to color %x\n", Color);
4189 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4190 glClearColor(D3DCOLOR_R(Color),
4191 D3DCOLOR_G(Color),
4192 D3DCOLOR_B(Color),
4193 D3DCOLOR_A(Color));
4194 checkGLcall("glClearColor");
4196 /* Clear ALL colors! */
4197 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4198 glMask = glMask | GL_COLOR_BUFFER_BIT;
4201 /* Now process each rect in turn */
4202 for (i = 0; i < Count || i == 0; i++) {
4204 if (curRect) {
4205 /* Note gl uses lower left, width/height */
4206 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4207 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4208 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4209 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4210 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4211 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4212 checkGLcall("glScissor");
4213 } else {
4214 glScissor(This->stateBlock->viewport.X,
4215 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4216 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4217 This->stateBlock->viewport.Width,
4218 This->stateBlock->viewport.Height);
4219 checkGLcall("glScissor");
4222 /* Clear the selected rectangle (or full screen) */
4223 glClear(glMask);
4224 checkGLcall("glClear");
4226 /* Step to the next rectangle */
4227 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4230 /* Restore the old values (why..?) */
4231 if (Flags & WINED3DCLEAR_STENCIL) {
4232 glClearStencil(old_stencil_clear_value);
4233 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4235 if (Flags & WINED3DCLEAR_ZBUFFER) {
4236 glDepthMask(old_ztest);
4237 glClearDepth(old_z_clear_value);
4239 if (Flags & WINED3DCLEAR_TARGET) {
4240 glClearColor(old_color_clear_value[0],
4241 old_color_clear_value[1],
4242 old_color_clear_value[2],
4243 old_color_clear_value[3]);
4244 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4245 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4246 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4247 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4250 glDisable(GL_SCISSOR_TEST);
4251 checkGLcall("glDisable");
4252 LEAVE_GL();
4254 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4255 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4257 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4258 return WINED3D_OK;
4261 /*****
4262 * Drawing functions
4263 *****/
4264 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4265 UINT PrimitiveCount) {
4267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4268 This->stateBlock->streamIsUP = FALSE;
4270 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4271 debug_d3dprimitivetype(PrimitiveType),
4272 StartVertex, PrimitiveCount);
4274 if(This->stateBlock->loadBaseVertexIndex != 0) {
4275 This->stateBlock->loadBaseVertexIndex = 0;
4276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4278 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4279 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4280 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4281 return WINED3D_OK;
4284 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4285 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4286 WINED3DPRIMITIVETYPE PrimitiveType,
4287 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4290 UINT idxStride = 2;
4291 IWineD3DIndexBuffer *pIB;
4292 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4294 pIB = This->stateBlock->pIndexData;
4295 This->stateBlock->streamIsUP = FALSE;
4297 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4298 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4299 minIndex, NumVertices, startIndex, primCount);
4301 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4302 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4303 idxStride = 2;
4304 } else {
4305 idxStride = 4;
4308 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4309 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4313 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4314 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4316 return WINED3D_OK;
4319 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4320 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4321 UINT VertexStreamZeroStride) {
4322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4324 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4325 debug_d3dprimitivetype(PrimitiveType),
4326 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4328 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4329 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4330 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4331 This->stateBlock->streamIsUP = TRUE;
4332 This->stateBlock->loadBaseVertexIndex = 0;
4334 /* TODO: Only mark dirty if drawing from a different UP address */
4335 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4337 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4338 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4340 /* MSDN specifies stream zero settings must be set to NULL */
4341 This->stateBlock->streamStride[0] = 0;
4342 This->stateBlock->streamSource[0] = NULL;
4344 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4345 * the new stream sources or use UP drawing again
4347 return WINED3D_OK;
4350 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4351 UINT MinVertexIndex, UINT NumVertices,
4352 UINT PrimitiveCount, CONST void* pIndexData,
4353 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4354 UINT VertexStreamZeroStride) {
4355 int idxStride;
4356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4358 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4359 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4360 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4361 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4363 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4364 idxStride = 2;
4365 } else {
4366 idxStride = 4;
4369 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4370 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4371 This->stateBlock->streamIsUP = TRUE;
4372 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4374 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4375 This->stateBlock->baseVertexIndex = 0;
4376 This->stateBlock->loadBaseVertexIndex = 0;
4377 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4380 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4382 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4383 This->stateBlock->streamSource[0] = NULL;
4384 This->stateBlock->streamStride[0] = 0;
4385 This->stateBlock->pIndexData = NULL;
4386 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4387 * SetStreamSource to specify a vertex buffer
4390 return WINED3D_OK;
4393 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4396 /* Mark the state dirty until we have nicer tracking
4397 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4398 * that value.
4400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4401 This->stateBlock->baseVertexIndex = 0;
4402 This->up_strided = DrawPrimStrideData;
4403 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4404 This->up_strided = NULL;
4405 return WINED3D_OK;
4407 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4408 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4410 HRESULT hr = WINED3D_OK;
4411 WINED3DRESOURCETYPE sourceType;
4412 WINED3DRESOURCETYPE destinationType;
4413 int i ,levels;
4415 /* TODO: think about moving the code into IWineD3DBaseTexture */
4417 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4419 /* verify that the source and destination textures aren't NULL */
4420 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4421 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4422 This, pSourceTexture, pDestinationTexture);
4423 hr = WINED3DERR_INVALIDCALL;
4426 if (pSourceTexture == pDestinationTexture) {
4427 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4428 This, pSourceTexture, pDestinationTexture);
4429 hr = WINED3DERR_INVALIDCALL;
4431 /* Verify that the source and destination textures are the same type */
4432 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4433 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4435 if (sourceType != destinationType) {
4436 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4437 This);
4438 hr = WINED3DERR_INVALIDCALL;
4441 /* check that both textures have the identical numbers of levels */
4442 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4443 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4444 hr = WINED3DERR_INVALIDCALL;
4447 if (WINED3D_OK == hr) {
4449 /* Make sure that the destination texture is loaded */
4450 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4452 /* Update every surface level of the texture */
4453 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4455 switch (sourceType) {
4456 case WINED3DRTYPE_TEXTURE:
4458 IWineD3DSurface *srcSurface;
4459 IWineD3DSurface *destSurface;
4461 for (i = 0 ; i < levels ; ++i) {
4462 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4463 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4464 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4465 IWineD3DSurface_Release(srcSurface);
4466 IWineD3DSurface_Release(destSurface);
4467 if (WINED3D_OK != hr) {
4468 WARN("(%p) : Call to update surface failed\n", This);
4469 return hr;
4473 break;
4474 case WINED3DRTYPE_CUBETEXTURE:
4476 IWineD3DSurface *srcSurface;
4477 IWineD3DSurface *destSurface;
4478 WINED3DCUBEMAP_FACES faceType;
4480 for (i = 0 ; i < levels ; ++i) {
4481 /* Update each cube face */
4482 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4483 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4484 if (WINED3D_OK != hr) {
4485 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4486 } else {
4487 TRACE("Got srcSurface %p\n", srcSurface);
4489 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4490 if (WINED3D_OK != hr) {
4491 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4492 } else {
4493 TRACE("Got desrSurface %p\n", destSurface);
4495 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4496 IWineD3DSurface_Release(srcSurface);
4497 IWineD3DSurface_Release(destSurface);
4498 if (WINED3D_OK != hr) {
4499 WARN("(%p) : Call to update surface failed\n", This);
4500 return hr;
4505 break;
4506 #if 0 /* TODO: Add support for volume textures */
4507 case WINED3DRTYPE_VOLUMETEXTURE:
4509 IWineD3DVolume srcVolume = NULL;
4510 IWineD3DSurface destVolume = NULL;
4512 for (i = 0 ; i < levels ; ++i) {
4513 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4514 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4515 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4516 IWineD3DVolume_Release(srcSurface);
4517 IWineD3DVolume_Release(destSurface);
4518 if (WINED3D_OK != hr) {
4519 WARN("(%p) : Call to update volume failed\n", This);
4520 return hr;
4524 break;
4525 #endif
4526 default:
4527 FIXME("(%p) : Unsupported source and destination type\n", This);
4528 hr = WINED3DERR_INVALIDCALL;
4532 return hr;
4535 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4536 IWineD3DSwapChain *swapChain;
4537 HRESULT hr;
4538 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4539 if(hr == WINED3D_OK) {
4540 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4541 IWineD3DSwapChain_Release(swapChain);
4543 return hr;
4546 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4548 /* return a sensible default */
4549 *pNumPasses = 1;
4550 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4551 FIXME("(%p) : stub\n", This);
4552 return WINED3D_OK;
4555 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4557 int j;
4558 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4559 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4560 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4561 return WINED3DERR_INVALIDCALL;
4563 for (j = 0; j < 256; ++j) {
4564 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4565 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4566 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4567 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4569 TRACE("(%p) : returning\n", This);
4570 return WINED3D_OK;
4573 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 int j;
4576 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4577 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4578 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4579 return WINED3DERR_INVALIDCALL;
4581 for (j = 0; j < 256; ++j) {
4582 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4583 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4584 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4585 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4587 TRACE("(%p) : returning\n", This);
4588 return WINED3D_OK;
4591 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4593 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4594 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4595 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4596 return WINED3DERR_INVALIDCALL;
4598 /*TODO: stateblocks */
4599 This->currentPalette = PaletteNumber;
4600 TRACE("(%p) : returning\n", This);
4601 return WINED3D_OK;
4604 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4606 if (PaletteNumber == NULL) {
4607 WARN("(%p) : returning Invalid Call\n", This);
4608 return WINED3DERR_INVALIDCALL;
4610 /*TODO: stateblocks */
4611 *PaletteNumber = This->currentPalette;
4612 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4613 return WINED3D_OK;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 static BOOL showFixmes = TRUE;
4619 if (showFixmes) {
4620 FIXME("(%p) : stub\n", This);
4621 showFixmes = FALSE;
4624 This->softwareVertexProcessing = bSoftware;
4625 return WINED3D_OK;
4629 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4631 static BOOL showFixmes = TRUE;
4632 if (showFixmes) {
4633 FIXME("(%p) : stub\n", This);
4634 showFixmes = FALSE;
4636 return This->softwareVertexProcessing;
4640 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 IWineD3DSwapChain *swapChain;
4643 HRESULT hr;
4645 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4647 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4648 if(hr == WINED3D_OK){
4649 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4650 IWineD3DSwapChain_Release(swapChain);
4651 }else{
4652 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4654 return hr;
4658 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 static BOOL showfixmes = TRUE;
4661 if(nSegments != 0.0f) {
4662 if( showfixmes) {
4663 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4664 showfixmes = FALSE;
4667 return WINED3D_OK;
4670 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 static BOOL showfixmes = TRUE;
4673 if( showfixmes) {
4674 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4675 showfixmes = FALSE;
4677 return 0.0f;
4680 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4682 /** TODO: remove casts to IWineD3DSurfaceImpl
4683 * NOTE: move code to surface to accomplish this
4684 ****************************************/
4685 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4686 int srcWidth, srcHeight;
4687 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4688 WINED3DFORMAT destFormat, srcFormat;
4689 UINT destSize;
4690 int srcLeft, destLeft, destTop;
4691 WINED3DPOOL srcPool, destPool;
4692 int offset = 0;
4693 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4694 glDescriptor *glDescription = NULL;
4695 GLenum textureDimensions = GL_TEXTURE_2D;
4696 IWineD3DBaseTexture *baseTexture;
4698 WINED3DSURFACE_DESC winedesc;
4700 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4701 memset(&winedesc, 0, sizeof(winedesc));
4702 winedesc.Width = &srcSurfaceWidth;
4703 winedesc.Height = &srcSurfaceHeight;
4704 winedesc.Pool = &srcPool;
4705 winedesc.Format = &srcFormat;
4707 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4709 winedesc.Width = &destSurfaceWidth;
4710 winedesc.Height = &destSurfaceHeight;
4711 winedesc.Pool = &destPool;
4712 winedesc.Format = &destFormat;
4713 winedesc.Size = &destSize;
4715 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4717 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4718 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4719 return WINED3DERR_INVALIDCALL;
4722 if (destFormat == WINED3DFMT_UNKNOWN) {
4723 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4724 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4726 /* Get the update surface description */
4727 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4730 /* Make sure the surface is loaded and up to date */
4731 IWineD3DSurface_PreLoad(pDestinationSurface);
4733 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4735 ENTER_GL();
4737 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4738 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4739 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4740 srcLeft = pSourceRect ? pSourceRect->left : 0;
4741 destLeft = pDestPoint ? pDestPoint->x : 0;
4742 destTop = pDestPoint ? pDestPoint->y : 0;
4745 /* This function doesn't support compressed textures
4746 the pitch is just bytesPerPixel * width */
4747 if(srcWidth != srcSurfaceWidth || srcLeft ){
4748 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4749 offset += srcLeft * pSrcSurface->bytesPerPixel;
4750 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4752 /* TODO DXT formats */
4754 if(pSourceRect != NULL && pSourceRect->top != 0){
4755 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4757 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4758 ,This
4759 ,glDescription->level
4760 ,destLeft
4761 ,destTop
4762 ,srcWidth
4763 ,srcHeight
4764 ,glDescription->glFormat
4765 ,glDescription->glType
4766 ,IWineD3DSurface_GetData(pSourceSurface)
4769 /* Sanity check */
4770 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4772 /* need to lock the surface to get the data */
4773 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4776 /* TODO: Cube and volume support */
4777 if(rowoffset != 0){
4778 /* not a whole row so we have to do it a line at a time */
4779 int j;
4781 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4782 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4784 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4786 glTexSubImage2D(glDescription->target
4787 ,glDescription->level
4788 ,destLeft
4790 ,srcWidth
4792 ,glDescription->glFormat
4793 ,glDescription->glType
4794 ,data /* could be quicker using */
4796 data += rowoffset;
4799 } else { /* Full width, so just write out the whole texture */
4801 if (WINED3DFMT_DXT1 == destFormat ||
4802 WINED3DFMT_DXT2 == destFormat ||
4803 WINED3DFMT_DXT3 == destFormat ||
4804 WINED3DFMT_DXT4 == destFormat ||
4805 WINED3DFMT_DXT5 == destFormat) {
4806 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4807 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4808 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4809 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4810 } if (destFormat != srcFormat) {
4811 FIXME("Updating mixed format compressed texture is not curretly support\n");
4812 } else {
4813 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4814 glDescription->level,
4815 glDescription->glFormatInternal,
4816 srcWidth,
4817 srcHeight,
4819 destSize,
4820 IWineD3DSurface_GetData(pSourceSurface));
4822 } else {
4823 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4827 } else {
4828 glTexSubImage2D(glDescription->target
4829 ,glDescription->level
4830 ,destLeft
4831 ,destTop
4832 ,srcWidth
4833 ,srcHeight
4834 ,glDescription->glFormat
4835 ,glDescription->glType
4836 ,IWineD3DSurface_GetData(pSourceSurface)
4840 checkGLcall("glTexSubImage2D");
4841 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4843 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4844 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4845 * surface bigger than it needs to be hmm.. */
4846 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4847 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4848 IWineD3DBaseTexture_Release(baseTexture);
4851 glDisable(textureDimensions); /* This needs to be managed better.... */
4852 LEAVE_GL();
4854 return WINED3D_OK;
4857 /* Implementation details at http://developer.nvidia.com/attach/6494
4859 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4860 hmm.. no longer supported use
4861 OpenGL evaluators or tessellate surfaces within your application.
4864 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4865 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4867 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4868 FIXME("(%p) : Stub\n", This);
4869 return WINED3D_OK;
4873 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4874 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4876 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4877 FIXME("(%p) : Stub\n", This);
4878 return WINED3D_OK;
4881 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4883 TRACE("(%p) Handle(%d)\n", This, Handle);
4884 FIXME("(%p) : Stub\n", This);
4885 return WINED3D_OK;
4888 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4890 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4891 DDBLTFX BltFx;
4892 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4894 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4895 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4896 return WINED3DERR_INVALIDCALL;
4899 /* Just forward this to the DirectDraw blitting engine */
4900 memset(&BltFx, 0, sizeof(BltFx));
4901 BltFx.dwSize = sizeof(BltFx);
4902 BltFx.u5.dwFillColor = color;
4903 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4906 /* rendertarget and deptth stencil functions */
4907 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4910 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4911 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4912 return WINED3DERR_INVALIDCALL;
4915 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4916 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4917 /* Note inc ref on returned surface */
4918 if(*ppRenderTarget != NULL)
4919 IWineD3DSurface_AddRef(*ppRenderTarget);
4920 return WINED3D_OK;
4923 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4926 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4927 IWineD3DSwapChainImpl *Swapchain;
4928 HRESULT hr;
4930 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4932 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4933 if(hr != WINED3D_OK) {
4934 ERR("Can't get the swapchain\n");
4935 return hr;
4938 /* Make sure to release the swapchain */
4939 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4941 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4942 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4943 return WINED3DERR_INVALIDCALL;
4945 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4946 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4947 return WINED3DERR_INVALIDCALL;
4950 if(Swapchain->frontBuffer != Front) {
4951 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4953 if(Swapchain->frontBuffer)
4954 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4955 Swapchain->frontBuffer = Front;
4957 if(Swapchain->frontBuffer) {
4958 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4962 if(Back && !Swapchain->backBuffer) {
4963 /* We need memory for the back buffer array - only one back buffer this way */
4964 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4965 if(!Swapchain->backBuffer) {
4966 ERR("Out of memory\n");
4967 return E_OUTOFMEMORY;
4971 if(Swapchain->backBuffer[0] != Back) {
4972 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4973 ENTER_GL();
4974 if(!Swapchain->backBuffer[0]) {
4975 /* GL was told to draw to the front buffer at creation,
4976 * undo that
4978 glDrawBuffer(GL_BACK);
4979 checkGLcall("glDrawBuffer(GL_BACK)");
4980 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4981 Swapchain->presentParms.BackBufferCount = 1;
4982 } else if (!Back) {
4983 /* That makes problems - disable for now */
4984 /* glDrawBuffer(GL_FRONT); */
4985 checkGLcall("glDrawBuffer(GL_FRONT)");
4986 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4987 Swapchain->presentParms.BackBufferCount = 0;
4989 LEAVE_GL();
4991 if(Swapchain->backBuffer[0])
4992 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4993 Swapchain->backBuffer[0] = Back;
4995 if(Swapchain->backBuffer[0]) {
4996 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4997 } else {
4998 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5003 return WINED3D_OK;
5006 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 *ppZStencilSurface = This->depthStencilBuffer;
5009 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5011 if(*ppZStencilSurface != NULL) {
5012 /* Note inc ref on returned surface */
5013 IWineD3DSurface_AddRef(*ppZStencilSurface);
5015 return WINED3D_OK;
5018 static void bind_fbo(IWineD3DDevice *iface) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5021 if (!This->fbo) {
5022 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5023 checkGLcall("glGenFramebuffersEXT()");
5025 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5026 checkGLcall("glBindFramebuffer()");
5029 /* TODO: Handle stencil attachments */
5030 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5032 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5034 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5036 bind_fbo(iface);
5038 if (depth_stencil_impl) {
5039 GLenum texttarget, target;
5040 GLint old_binding = 0;
5042 IWineD3DSurface_PreLoad(depth_stencil);
5043 texttarget = depth_stencil_impl->glDescription.target;
5044 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5046 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5047 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5048 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5049 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5050 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5051 glBindTexture(target, old_binding);
5053 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5054 checkGLcall("glFramebufferTexture2DEXT()");
5055 } else {
5056 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5057 checkGLcall("glFramebufferTexture2DEXT()");
5060 if (!This->render_offscreen) {
5061 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5062 checkGLcall("glBindFramebuffer()");
5066 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5068 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5070 if (idx >= GL_LIMITS(buffers)) {
5071 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5074 bind_fbo(iface);
5076 if (rtimpl) {
5077 GLenum texttarget, target;
5078 GLint old_binding = 0;
5080 IWineD3DSurface_PreLoad(render_target);
5081 texttarget = rtimpl->glDescription.target;
5082 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5084 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5085 glBindTexture(target, rtimpl->glDescription.textureName);
5086 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5087 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5088 glBindTexture(target, old_binding);
5090 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5091 checkGLcall("glFramebufferTexture2DEXT()");
5093 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5094 } else {
5095 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5096 checkGLcall("glFramebufferTexture2DEXT()");
5098 This->draw_buffers[idx] = GL_NONE;
5101 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5102 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5103 checkGLcall("glDrawBuffers()");
5106 if (!This->render_offscreen) {
5107 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5108 checkGLcall("glBindFramebuffer()");
5112 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5114 WINED3DVIEWPORT viewport;
5116 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5118 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5119 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5120 return WINED3DERR_INVALIDCALL;
5123 /* MSDN says that null disables the render target
5124 but a device must always be associated with a render target
5125 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5127 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5128 for more details
5130 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5131 FIXME("Trying to set render target 0 to NULL\n");
5132 return WINED3DERR_INVALIDCALL;
5134 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5135 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);
5136 return WINED3DERR_INVALIDCALL;
5139 /* If we are trying to set what we already have, don't bother */
5140 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5141 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5142 return WINED3D_OK;
5144 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5145 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5146 This->render_targets[RenderTargetIndex] = pRenderTarget;
5148 /* Render target 0 is special */
5149 if(RenderTargetIndex == 0) {
5150 /* Finally, reset the viewport as the MSDN states. */
5151 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5152 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5153 viewport.X = 0;
5154 viewport.Y = 0;
5155 viewport.MaxZ = 1.0f;
5156 viewport.MinZ = 0.0f;
5157 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5159 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5160 * ctx properly.
5161 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5162 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5164 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5165 } else {
5166 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5167 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5169 return WINED3D_OK;
5172 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5174 HRESULT hr = WINED3D_OK;
5175 IWineD3DSurface *tmp;
5177 TRACE("(%p) Swapping z-buffer\n",This);
5179 if (pNewZStencil == This->stencilBufferTarget) {
5180 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5181 } else {
5182 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5183 * depending on the renter target implementation being used.
5184 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5185 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5186 * stencil buffer and incure an extra memory overhead
5187 ******************************************************/
5190 tmp = This->stencilBufferTarget;
5191 This->stencilBufferTarget = pNewZStencil;
5192 /* should we be calling the parent or the wined3d surface? */
5193 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5194 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5195 hr = WINED3D_OK;
5196 /** TODO: glEnable/glDisable on depth/stencil depending on
5197 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5198 **********************************************************/
5199 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5200 set_depth_stencil_fbo(iface, pNewZStencil);
5204 return hr;
5207 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5208 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5210 /* TODO: the use of Impl is deprecated. */
5211 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5213 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5215 /* some basic validation checks */
5216 if(This->cursorTexture) {
5217 ENTER_GL();
5218 glDeleteTextures(1, &This->cursorTexture);
5219 LEAVE_GL();
5220 This->cursorTexture = 0;
5223 if(pCursorBitmap) {
5224 /* MSDN: Cursor must be A8R8G8B8 */
5225 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5226 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5227 return WINED3DERR_INVALIDCALL;
5230 /* MSDN: Cursor must be smaller than the display mode */
5231 if(pSur->currentDesc.Width > This->ddraw_width ||
5232 pSur->currentDesc.Height > This->ddraw_height) {
5233 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);
5234 return WINED3DERR_INVALIDCALL;
5237 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5238 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5239 * Texture and Blitting code to draw the cursor
5241 pSur->Flags |= SFLAG_FORCELOAD;
5242 IWineD3DSurface_PreLoad(pCursorBitmap);
5243 pSur->Flags &= ~SFLAG_FORCELOAD;
5244 /* Do not store the surface's pointer because the application may release
5245 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5246 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5248 This->cursorTexture = pSur->glDescription.textureName;
5249 This->cursorWidth = pSur->currentDesc.Width;
5250 This->cursorHeight = pSur->currentDesc.Height;
5251 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5254 This->xHotSpot = XHotSpot;
5255 This->yHotSpot = YHotSpot;
5256 return WINED3D_OK;
5259 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5261 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5263 This->xScreenSpace = XScreenSpace;
5264 This->yScreenSpace = YScreenSpace;
5266 return;
5270 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5272 BOOL oldVisible = This->bCursorVisible;
5273 TRACE("(%p) : visible(%d)\n", This, bShow);
5275 if(This->cursorTexture)
5276 This->bCursorVisible = bShow;
5278 return oldVisible;
5281 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5283 TRACE("(%p) : state (%u)\n", This, This->state);
5284 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5285 switch (This->state) {
5286 case WINED3D_OK:
5287 return WINED3D_OK;
5288 case WINED3DERR_DEVICELOST:
5290 ResourceList *resourceList = This->resources;
5291 while (NULL != resourceList) {
5292 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5293 return WINED3DERR_DEVICENOTRESET;
5294 resourceList = resourceList->next;
5296 return WINED3DERR_DEVICELOST;
5298 case WINED3DERR_DRIVERINTERNALERROR:
5299 return WINED3DERR_DRIVERINTERNALERROR;
5302 /* Unknown state */
5303 return WINED3DERR_DRIVERINTERNALERROR;
5307 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5309 /** FIXME: Resource tracking needs to be done,
5310 * The closes we can do to this is set the priorities of all managed textures low
5311 * and then reset them.
5312 ***********************************************************/
5313 FIXME("(%p) : stub\n", This);
5314 return WINED3D_OK;
5317 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5318 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5320 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5321 if(surface->Flags & SFLAG_DIBSECTION) {
5322 /* Release the DC */
5323 SelectObject(surface->hDC, surface->dib.holdbitmap);
5324 DeleteDC(surface->hDC);
5325 /* Release the DIB section */
5326 DeleteObject(surface->dib.DIBsection);
5327 surface->dib.bitmap_data = NULL;
5328 surface->resource.allocatedMemory = NULL;
5329 surface->Flags &= ~SFLAG_DIBSECTION;
5331 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5332 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5333 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5334 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5335 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5336 } else {
5337 surface->pow2Width = surface->pow2Height = 1;
5338 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5339 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5341 if(surface->glDescription.textureName) {
5342 ENTER_GL();
5343 glDeleteTextures(1, &surface->glDescription.textureName);
5344 LEAVE_GL();
5345 surface->glDescription.textureName = 0;
5347 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5348 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5349 surface->Flags |= SFLAG_NONPOW2;
5350 } else {
5351 surface->Flags &= ~SFLAG_NONPOW2;
5353 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5354 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5357 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5359 IWineD3DSwapChainImpl *swapchain;
5360 HRESULT hr;
5361 BOOL DisplayModeChanged = FALSE;
5362 WINED3DDISPLAYMODE mode;
5363 TRACE("(%p)\n", This);
5365 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5366 if(FAILED(hr)) {
5367 ERR("Failed to get the first implicit swapchain\n");
5368 return hr;
5371 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5372 * on an existing gl context, so there's no real need for recreation.
5374 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5376 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5378 TRACE("New params:\n");
5379 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5380 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5381 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5382 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5383 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5384 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5385 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5386 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5387 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5388 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5389 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5390 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5391 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5393 /* No special treatment of these parameters. Just store them */
5394 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5395 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5396 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5397 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5399 /* What to do about these? */
5400 if(pPresentationParameters->BackBufferCount != 0 &&
5401 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5402 ERR("Cannot change the back buffer count yet\n");
5404 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5405 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5406 ERR("Cannot change the back buffer format yet\n");
5408 if(pPresentationParameters->hDeviceWindow != NULL &&
5409 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5410 ERR("Cannot change the device window yet\n");
5412 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5413 ERR("What do do about a changed auto depth stencil parameter?\n");
5416 if(pPresentationParameters->Windowed) {
5417 mode.Width = swapchain->orig_width;
5418 mode.Height = swapchain->orig_height;
5419 mode.RefreshRate = 0;
5420 mode.Format = swapchain->presentParms.BackBufferFormat;
5421 } else {
5422 mode.Width = pPresentationParameters->BackBufferWidth;
5423 mode.Height = pPresentationParameters->BackBufferHeight;
5424 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5425 mode.Format = swapchain->presentParms.BackBufferFormat;
5428 /* Should Width == 800 && Height == 0 set 800x600? */
5429 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5430 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5431 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5433 WINED3DVIEWPORT vp;
5434 int i;
5436 vp.X = 0;
5437 vp.Y = 0;
5438 vp.Width = pPresentationParameters->BackBufferWidth;
5439 vp.Height = pPresentationParameters->BackBufferHeight;
5440 vp.MinZ = 0;
5441 vp.MaxZ = 1;
5443 if(!pPresentationParameters->Windowed) {
5444 DisplayModeChanged = TRUE;
5446 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5447 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5449 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5450 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5451 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5454 /* Now set the new viewport */
5455 IWineD3DDevice_SetViewport(iface, &vp);
5458 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5459 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5460 DisplayModeChanged) {
5462 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5463 if(!pPresentationParameters->Windowed) {
5464 IWineD3DDevice_SetFullscreen(iface, TRUE);
5467 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5469 /* Switching out of fullscreen mode? First set the original res, then change the window */
5470 if(pPresentationParameters->Windowed) {
5471 IWineD3DDevice_SetFullscreen(iface, FALSE);
5473 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5476 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5477 return WINED3D_OK;
5480 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5482 /** FIXME: always true at the moment **/
5483 if(!bEnableDialogs) {
5484 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5486 return WINED3D_OK;
5490 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5492 TRACE("(%p) : pParameters %p\n", This, pParameters);
5494 *pParameters = This->createParms;
5495 return WINED3D_OK;
5498 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5499 IWineD3DSwapChain *swapchain;
5500 HRESULT hrc = WINED3D_OK;
5502 TRACE("Relaying to swapchain\n");
5504 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5505 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5506 IWineD3DSwapChain_Release(swapchain);
5508 return;
5511 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5512 IWineD3DSwapChain *swapchain;
5513 HRESULT hrc = WINED3D_OK;
5515 TRACE("Relaying to swapchain\n");
5517 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5518 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5519 IWineD3DSwapChain_Release(swapchain);
5521 return;
5525 /** ********************************************************
5526 * Notification functions
5527 ** ********************************************************/
5528 /** This function must be called in the release of a resource when ref == 0,
5529 * the contents of resource must still be correct,
5530 * any handels to other resource held by the caller must be closed
5531 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5532 *****************************************************/
5533 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5535 ResourceList* resourceList;
5537 TRACE("(%p) : resource %p\n", This, resource);
5538 #if 0
5539 EnterCriticalSection(&resourceStoreCriticalSection);
5540 #endif
5541 /* add a new texture to the frot of the linked list */
5542 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5543 resourceList->resource = resource;
5545 /* Get the old head */
5546 resourceList->next = This->resources;
5548 This->resources = resourceList;
5549 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5551 #if 0
5552 LeaveCriticalSection(&resourceStoreCriticalSection);
5553 #endif
5554 return;
5557 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5559 ResourceList* resourceList = NULL;
5560 ResourceList* previousResourceList = NULL;
5562 TRACE("(%p) : resource %p\n", This, resource);
5564 #if 0
5565 EnterCriticalSection(&resourceStoreCriticalSection);
5566 #endif
5567 resourceList = This->resources;
5569 while (resourceList != NULL) {
5570 if(resourceList->resource == resource) break;
5571 previousResourceList = resourceList;
5572 resourceList = resourceList->next;
5575 if (resourceList == NULL) {
5576 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5577 #if 0
5578 LeaveCriticalSection(&resourceStoreCriticalSection);
5579 #endif
5580 return;
5581 } else {
5582 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5584 /* make sure we don't leave a hole in the list */
5585 if (previousResourceList != NULL) {
5586 previousResourceList->next = resourceList->next;
5587 } else {
5588 This->resources = resourceList->next;
5591 #if 0
5592 LeaveCriticalSection(&resourceStoreCriticalSection);
5593 #endif
5594 return;
5598 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5600 int counter;
5602 TRACE("(%p) : resource %p\n", This, resource);
5603 switch(IWineD3DResource_GetType(resource)){
5604 case WINED3DRTYPE_SURFACE:
5605 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5606 break;
5607 case WINED3DRTYPE_TEXTURE:
5608 case WINED3DRTYPE_CUBETEXTURE:
5609 case WINED3DRTYPE_VOLUMETEXTURE:
5610 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5611 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5612 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5613 This->stateBlock->textures[counter] = NULL;
5615 if (This->updateStateBlock != This->stateBlock ){
5616 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5617 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5618 This->updateStateBlock->textures[counter] = NULL;
5622 break;
5623 case WINED3DRTYPE_VOLUME:
5624 /* TODO: nothing really? */
5625 break;
5626 case WINED3DRTYPE_VERTEXBUFFER:
5627 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5629 int streamNumber;
5630 TRACE("Cleaning up stream pointers\n");
5632 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5633 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5634 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5636 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5637 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5638 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5639 This->updateStateBlock->streamSource[streamNumber] = 0;
5640 /* Set changed flag? */
5643 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) */
5644 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5645 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5646 This->stateBlock->streamSource[streamNumber] = 0;
5649 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5650 else { /* This shouldn't happen */
5651 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5653 #endif
5657 break;
5658 case WINED3DRTYPE_INDEXBUFFER:
5659 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5660 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5661 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5662 This->updateStateBlock->pIndexData = NULL;
5665 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5666 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5667 This->stateBlock->pIndexData = NULL;
5671 break;
5672 default:
5673 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5674 break;
5678 /* Remove the resoruce from the resourceStore */
5679 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5681 TRACE("Resource released\n");
5685 /**********************************************************
5686 * IWineD3DDevice VTbl follows
5687 **********************************************************/
5689 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5691 /*** IUnknown methods ***/
5692 IWineD3DDeviceImpl_QueryInterface,
5693 IWineD3DDeviceImpl_AddRef,
5694 IWineD3DDeviceImpl_Release,
5695 /*** IWineD3DDevice methods ***/
5696 IWineD3DDeviceImpl_GetParent,
5697 /*** Creation methods**/
5698 IWineD3DDeviceImpl_CreateVertexBuffer,
5699 IWineD3DDeviceImpl_CreateIndexBuffer,
5700 IWineD3DDeviceImpl_CreateStateBlock,
5701 IWineD3DDeviceImpl_CreateSurface,
5702 IWineD3DDeviceImpl_CreateTexture,
5703 IWineD3DDeviceImpl_CreateVolumeTexture,
5704 IWineD3DDeviceImpl_CreateVolume,
5705 IWineD3DDeviceImpl_CreateCubeTexture,
5706 IWineD3DDeviceImpl_CreateQuery,
5707 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5708 IWineD3DDeviceImpl_CreateVertexDeclaration,
5709 IWineD3DDeviceImpl_CreateVertexShader,
5710 IWineD3DDeviceImpl_CreatePixelShader,
5711 IWineD3DDeviceImpl_CreatePalette,
5712 /*** Odd functions **/
5713 IWineD3DDeviceImpl_Init3D,
5714 IWineD3DDeviceImpl_Uninit3D,
5715 IWineD3DDeviceImpl_SetFullscreen,
5716 IWineD3DDeviceImpl_EnumDisplayModes,
5717 IWineD3DDeviceImpl_EvictManagedResources,
5718 IWineD3DDeviceImpl_GetAvailableTextureMem,
5719 IWineD3DDeviceImpl_GetBackBuffer,
5720 IWineD3DDeviceImpl_GetCreationParameters,
5721 IWineD3DDeviceImpl_GetDeviceCaps,
5722 IWineD3DDeviceImpl_GetDirect3D,
5723 IWineD3DDeviceImpl_GetDisplayMode,
5724 IWineD3DDeviceImpl_SetDisplayMode,
5725 IWineD3DDeviceImpl_GetHWND,
5726 IWineD3DDeviceImpl_SetHWND,
5727 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5728 IWineD3DDeviceImpl_GetRasterStatus,
5729 IWineD3DDeviceImpl_GetSwapChain,
5730 IWineD3DDeviceImpl_Reset,
5731 IWineD3DDeviceImpl_SetDialogBoxMode,
5732 IWineD3DDeviceImpl_SetCursorProperties,
5733 IWineD3DDeviceImpl_SetCursorPosition,
5734 IWineD3DDeviceImpl_ShowCursor,
5735 IWineD3DDeviceImpl_TestCooperativeLevel,
5736 /*** Getters and setters **/
5737 IWineD3DDeviceImpl_SetClipPlane,
5738 IWineD3DDeviceImpl_GetClipPlane,
5739 IWineD3DDeviceImpl_SetClipStatus,
5740 IWineD3DDeviceImpl_GetClipStatus,
5741 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5742 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5743 IWineD3DDeviceImpl_SetDepthStencilSurface,
5744 IWineD3DDeviceImpl_GetDepthStencilSurface,
5745 IWineD3DDeviceImpl_SetFVF,
5746 IWineD3DDeviceImpl_GetFVF,
5747 IWineD3DDeviceImpl_SetGammaRamp,
5748 IWineD3DDeviceImpl_GetGammaRamp,
5749 IWineD3DDeviceImpl_SetIndices,
5750 IWineD3DDeviceImpl_GetIndices,
5751 IWineD3DDeviceImpl_SetBasevertexIndex,
5752 IWineD3DDeviceImpl_SetLight,
5753 IWineD3DDeviceImpl_GetLight,
5754 IWineD3DDeviceImpl_SetLightEnable,
5755 IWineD3DDeviceImpl_GetLightEnable,
5756 IWineD3DDeviceImpl_SetMaterial,
5757 IWineD3DDeviceImpl_GetMaterial,
5758 IWineD3DDeviceImpl_SetNPatchMode,
5759 IWineD3DDeviceImpl_GetNPatchMode,
5760 IWineD3DDeviceImpl_SetPaletteEntries,
5761 IWineD3DDeviceImpl_GetPaletteEntries,
5762 IWineD3DDeviceImpl_SetPixelShader,
5763 IWineD3DDeviceImpl_GetPixelShader,
5764 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5765 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5766 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5767 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5768 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5769 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5770 IWineD3DDeviceImpl_SetRenderState,
5771 IWineD3DDeviceImpl_GetRenderState,
5772 IWineD3DDeviceImpl_SetRenderTarget,
5773 IWineD3DDeviceImpl_GetRenderTarget,
5774 IWineD3DDeviceImpl_SetFrontBackBuffers,
5775 IWineD3DDeviceImpl_SetSamplerState,
5776 IWineD3DDeviceImpl_GetSamplerState,
5777 IWineD3DDeviceImpl_SetScissorRect,
5778 IWineD3DDeviceImpl_GetScissorRect,
5779 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5780 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5781 IWineD3DDeviceImpl_SetStreamSource,
5782 IWineD3DDeviceImpl_GetStreamSource,
5783 IWineD3DDeviceImpl_SetStreamSourceFreq,
5784 IWineD3DDeviceImpl_GetStreamSourceFreq,
5785 IWineD3DDeviceImpl_SetTexture,
5786 IWineD3DDeviceImpl_GetTexture,
5787 IWineD3DDeviceImpl_SetTextureStageState,
5788 IWineD3DDeviceImpl_GetTextureStageState,
5789 IWineD3DDeviceImpl_SetTransform,
5790 IWineD3DDeviceImpl_GetTransform,
5791 IWineD3DDeviceImpl_SetVertexDeclaration,
5792 IWineD3DDeviceImpl_GetVertexDeclaration,
5793 IWineD3DDeviceImpl_SetVertexShader,
5794 IWineD3DDeviceImpl_GetVertexShader,
5795 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5796 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5797 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5798 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5799 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5800 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5801 IWineD3DDeviceImpl_SetViewport,
5802 IWineD3DDeviceImpl_GetViewport,
5803 IWineD3DDeviceImpl_MultiplyTransform,
5804 IWineD3DDeviceImpl_ValidateDevice,
5805 IWineD3DDeviceImpl_ProcessVertices,
5806 /*** State block ***/
5807 IWineD3DDeviceImpl_BeginStateBlock,
5808 IWineD3DDeviceImpl_EndStateBlock,
5809 /*** Scene management ***/
5810 IWineD3DDeviceImpl_BeginScene,
5811 IWineD3DDeviceImpl_EndScene,
5812 IWineD3DDeviceImpl_Present,
5813 IWineD3DDeviceImpl_Clear,
5814 /*** Drawing ***/
5815 IWineD3DDeviceImpl_DrawPrimitive,
5816 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5817 IWineD3DDeviceImpl_DrawPrimitiveUP,
5818 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5819 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5820 IWineD3DDeviceImpl_DrawRectPatch,
5821 IWineD3DDeviceImpl_DrawTriPatch,
5822 IWineD3DDeviceImpl_DeletePatch,
5823 IWineD3DDeviceImpl_ColorFill,
5824 IWineD3DDeviceImpl_UpdateTexture,
5825 IWineD3DDeviceImpl_UpdateSurface,
5826 IWineD3DDeviceImpl_GetFrontBufferData,
5827 /*** object tracking ***/
5828 IWineD3DDeviceImpl_ResourceReleased
5832 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5833 WINED3DRS_ALPHABLENDENABLE ,
5834 WINED3DRS_ALPHAFUNC ,
5835 WINED3DRS_ALPHAREF ,
5836 WINED3DRS_ALPHATESTENABLE ,
5837 WINED3DRS_BLENDOP ,
5838 WINED3DRS_COLORWRITEENABLE ,
5839 WINED3DRS_DESTBLEND ,
5840 WINED3DRS_DITHERENABLE ,
5841 WINED3DRS_FILLMODE ,
5842 WINED3DRS_FOGDENSITY ,
5843 WINED3DRS_FOGEND ,
5844 WINED3DRS_FOGSTART ,
5845 WINED3DRS_LASTPIXEL ,
5846 WINED3DRS_SHADEMODE ,
5847 WINED3DRS_SRCBLEND ,
5848 WINED3DRS_STENCILENABLE ,
5849 WINED3DRS_STENCILFAIL ,
5850 WINED3DRS_STENCILFUNC ,
5851 WINED3DRS_STENCILMASK ,
5852 WINED3DRS_STENCILPASS ,
5853 WINED3DRS_STENCILREF ,
5854 WINED3DRS_STENCILWRITEMASK ,
5855 WINED3DRS_STENCILZFAIL ,
5856 WINED3DRS_TEXTUREFACTOR ,
5857 WINED3DRS_WRAP0 ,
5858 WINED3DRS_WRAP1 ,
5859 WINED3DRS_WRAP2 ,
5860 WINED3DRS_WRAP3 ,
5861 WINED3DRS_WRAP4 ,
5862 WINED3DRS_WRAP5 ,
5863 WINED3DRS_WRAP6 ,
5864 WINED3DRS_WRAP7 ,
5865 WINED3DRS_ZENABLE ,
5866 WINED3DRS_ZFUNC ,
5867 WINED3DRS_ZWRITEENABLE
5870 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5871 WINED3DTSS_ADDRESSW ,
5872 WINED3DTSS_ALPHAARG0 ,
5873 WINED3DTSS_ALPHAARG1 ,
5874 WINED3DTSS_ALPHAARG2 ,
5875 WINED3DTSS_ALPHAOP ,
5876 WINED3DTSS_BUMPENVLOFFSET ,
5877 WINED3DTSS_BUMPENVLSCALE ,
5878 WINED3DTSS_BUMPENVMAT00 ,
5879 WINED3DTSS_BUMPENVMAT01 ,
5880 WINED3DTSS_BUMPENVMAT10 ,
5881 WINED3DTSS_BUMPENVMAT11 ,
5882 WINED3DTSS_COLORARG0 ,
5883 WINED3DTSS_COLORARG1 ,
5884 WINED3DTSS_COLORARG2 ,
5885 WINED3DTSS_COLOROP ,
5886 WINED3DTSS_RESULTARG ,
5887 WINED3DTSS_TEXCOORDINDEX ,
5888 WINED3DTSS_TEXTURETRANSFORMFLAGS
5891 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5892 WINED3DSAMP_ADDRESSU ,
5893 WINED3DSAMP_ADDRESSV ,
5894 WINED3DSAMP_ADDRESSW ,
5895 WINED3DSAMP_BORDERCOLOR ,
5896 WINED3DSAMP_MAGFILTER ,
5897 WINED3DSAMP_MINFILTER ,
5898 WINED3DSAMP_MIPFILTER ,
5899 WINED3DSAMP_MIPMAPLODBIAS ,
5900 WINED3DSAMP_MAXMIPLEVEL ,
5901 WINED3DSAMP_MAXANISOTROPY ,
5902 WINED3DSAMP_SRGBTEXTURE ,
5903 WINED3DSAMP_ELEMENTINDEX
5906 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5907 WINED3DRS_AMBIENT ,
5908 WINED3DRS_AMBIENTMATERIALSOURCE ,
5909 WINED3DRS_CLIPPING ,
5910 WINED3DRS_CLIPPLANEENABLE ,
5911 WINED3DRS_COLORVERTEX ,
5912 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5913 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5914 WINED3DRS_FOGDENSITY ,
5915 WINED3DRS_FOGEND ,
5916 WINED3DRS_FOGSTART ,
5917 WINED3DRS_FOGTABLEMODE ,
5918 WINED3DRS_FOGVERTEXMODE ,
5919 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5920 WINED3DRS_LIGHTING ,
5921 WINED3DRS_LOCALVIEWER ,
5922 WINED3DRS_MULTISAMPLEANTIALIAS ,
5923 WINED3DRS_MULTISAMPLEMASK ,
5924 WINED3DRS_NORMALIZENORMALS ,
5925 WINED3DRS_PATCHEDGESTYLE ,
5926 WINED3DRS_POINTSCALE_A ,
5927 WINED3DRS_POINTSCALE_B ,
5928 WINED3DRS_POINTSCALE_C ,
5929 WINED3DRS_POINTSCALEENABLE ,
5930 WINED3DRS_POINTSIZE ,
5931 WINED3DRS_POINTSIZE_MAX ,
5932 WINED3DRS_POINTSIZE_MIN ,
5933 WINED3DRS_POINTSPRITEENABLE ,
5934 WINED3DRS_RANGEFOGENABLE ,
5935 WINED3DRS_SPECULARMATERIALSOURCE ,
5936 WINED3DRS_TWEENFACTOR ,
5937 WINED3DRS_VERTEXBLEND
5940 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5941 WINED3DTSS_TEXCOORDINDEX ,
5942 WINED3DTSS_TEXTURETRANSFORMFLAGS
5945 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5946 WINED3DSAMP_DMAPOFFSET
5949 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5950 DWORD rep = StateTable[state].representative;
5951 DWORD idx;
5952 BYTE shift;
5953 UINT i;
5954 WineD3DContext *context;
5956 if(!rep) return;
5957 for(i = 0; i < This->numContexts; i++) {
5958 context = This->contexts[i];
5959 if(isStateDirty(context, rep)) continue;
5961 context->dirtyArray[context->numDirtyEntries++] = rep;
5962 idx = rep >> 5;
5963 shift = rep & 0x1f;
5964 context->isStateDirty[idx] |= (1 << shift);