wined3d: Use WINED3DPRESENT_BACK_BUFFER_MAX rather than D3DPRESENT_BACK_BUFFER_MAX.
[wine/wine-gecko.git] / dlls / wined3d / device.c
blobf511108374484957f44df35ebf58bd7deae41cb9
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 /* Create the volume */
943 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
944 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
946 /* Set its container to this object */
947 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
949 /* calcualte the next mipmap level */
950 tmpW = max(1, tmpW >> 1);
951 tmpH = max(1, tmpH >> 1);
952 tmpD = max(1, tmpD >> 1);
955 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
956 TRACE("(%p) : Created volume texture %p\n", This, object);
957 return WINED3D_OK;
960 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
961 UINT Width, UINT Height, UINT Depth,
962 DWORD Usage,
963 WINED3DFORMAT Format, WINED3DPOOL Pool,
964 IWineD3DVolume** ppVolume,
965 HANDLE* pSharedHandle, IUnknown *parent) {
967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
968 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
969 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
971 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
973 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
974 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
976 object->currentDesc.Width = Width;
977 object->currentDesc.Height = Height;
978 object->currentDesc.Depth = Depth;
979 object->bytesPerPixel = formatDesc->bpp;
981 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
982 object->lockable = TRUE;
983 object->locked = FALSE;
984 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
985 object->dirty = TRUE;
987 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
990 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
991 UINT Levels, DWORD Usage,
992 WINED3DFORMAT Format, WINED3DPOOL Pool,
993 IWineD3DCubeTexture **ppCubeTexture,
994 HANDLE *pSharedHandle, IUnknown *parent,
995 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
998 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
999 unsigned int i, j;
1000 UINT tmpW;
1001 HRESULT hr;
1002 unsigned int pow2EdgeLength = EdgeLength;
1004 /* TODO: It should only be possible to create textures for formats
1005 that are reported as supported */
1006 if (WINED3DFMT_UNKNOWN >= Format) {
1007 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1008 return WINED3DERR_INVALIDCALL;
1011 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1012 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1014 TRACE("(%p) Create Cube Texture\n", This);
1016 /** Non-power2 support **/
1018 /* Find the nearest pow2 match */
1019 pow2EdgeLength = 1;
1020 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1022 object->edgeLength = EdgeLength;
1023 /* TODO: support for native non-power 2 */
1024 /* Precalculated scaling for 'faked' non power of two texture coords */
1025 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1027 /* Calculate levels for mip mapping */
1028 if (Levels == 0) {
1029 object->baseTexture.levels++;
1030 tmpW = EdgeLength;
1031 while (tmpW > 1) {
1032 tmpW = max(1, tmpW >> 1);
1033 object->baseTexture.levels++;
1035 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1038 /* Generate all the surfaces */
1039 tmpW = EdgeLength;
1040 for (i = 0; i < object->baseTexture.levels; i++) {
1042 /* Create the 6 faces */
1043 for (j = 0; j < 6; j++) {
1045 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1046 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1048 if(hr!= WINED3D_OK) {
1049 /* clean up */
1050 int k;
1051 int l;
1052 for (l = 0; l < j; l++) {
1053 IWineD3DSurface_Release(object->surfaces[j][i]);
1055 for (k = 0; k < i; k++) {
1056 for (l = 0; l < 6; l++) {
1057 IWineD3DSurface_Release(object->surfaces[l][j]);
1061 FIXME("(%p) Failed to create surface\n",object);
1062 HeapFree(GetProcessHeap(),0,object);
1063 *ppCubeTexture = NULL;
1064 return hr;
1066 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1067 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1069 tmpW = max(1, tmpW >> 1);
1072 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1073 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1074 return WINED3D_OK;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1081 if (NULL == ppQuery) {
1082 /* Just a check to see if we support this type of query */
1083 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1084 switch(Type) {
1085 case WINED3DQUERYTYPE_OCCLUSION:
1086 TRACE("(%p) occlusion query\n", This);
1087 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1088 hr = WINED3D_OK;
1089 else
1090 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1091 break;
1092 case WINED3DQUERYTYPE_VCACHE:
1093 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1094 case WINED3DQUERYTYPE_VERTEXSTATS:
1095 case WINED3DQUERYTYPE_EVENT:
1096 case WINED3DQUERYTYPE_TIMESTAMP:
1097 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1098 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1099 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1100 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1101 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1102 case WINED3DQUERYTYPE_PIXELTIMINGS:
1103 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1104 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1105 default:
1106 FIXME("(%p) Unhandled query type %d\n", This, Type);
1108 return hr;
1111 D3DCREATEOBJECTINSTANCE(object, Query)
1112 object->type = Type;
1113 /* allocated the 'extended' data based on the type of query requested */
1114 switch(Type){
1115 case WINED3DQUERYTYPE_OCCLUSION:
1116 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1117 TRACE("(%p) Allocating data for an occlusion query\n", This);
1118 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1119 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1120 break;
1122 case WINED3DQUERYTYPE_VCACHE:
1123 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1124 case WINED3DQUERYTYPE_VERTEXSTATS:
1125 case WINED3DQUERYTYPE_EVENT:
1126 case WINED3DQUERYTYPE_TIMESTAMP:
1127 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1128 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1129 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1130 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1131 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1132 case WINED3DQUERYTYPE_PIXELTIMINGS:
1133 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1134 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1135 default:
1136 object->extendedData = 0;
1137 FIXME("(%p) Unhandled query type %d\n",This , Type);
1139 TRACE("(%p) : Created Query %p\n", This, object);
1140 return WINED3D_OK;
1143 /*****************************************************************************
1144 * IWineD3DDeviceImpl_SetupFullscreenWindow
1146 * Helper function that modifies a HWND's Style and ExStyle for proper
1147 * fullscreen use.
1149 * Params:
1150 * iface: Pointer to the IWineD3DDevice interface
1151 * window: Window to setup
1153 *****************************************************************************/
1154 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1157 LONG style, exStyle;
1158 /* Don't do anything if an original style is stored.
1159 * That shouldn't happen
1161 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1162 if (This->style || This->exStyle) {
1163 ERR("(%p): Want to change the window parameters of HWND %p, but "
1164 "another style is stored for restoration afterwards\n", This, window);
1167 /* Get the parameters and save them */
1168 style = GetWindowLongW(window, GWL_STYLE);
1169 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1170 This->style = style;
1171 This->exStyle = exStyle;
1173 /* Filter out window decorations */
1174 style &= ~WS_CAPTION;
1175 style &= ~WS_THICKFRAME;
1176 exStyle &= ~WS_EX_WINDOWEDGE;
1177 exStyle &= ~WS_EX_CLIENTEDGE;
1179 /* Make sure the window is managed, otherwise we won't get keyboard input */
1180 style |= WS_POPUP | WS_SYSMENU;
1182 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1183 This->style, This->exStyle, style, exStyle);
1185 SetWindowLongW(window, GWL_STYLE, style);
1186 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1188 /* Inform the window about the update. */
1189 SetWindowPos(window, HWND_TOP, 0, 0,
1190 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1191 ShowWindow(window, TRUE);
1194 /*****************************************************************************
1195 * IWineD3DDeviceImpl_RestoreWindow
1197 * Helper function that restores a windows' properties when taking it out
1198 * of fullscreen mode
1200 * Params:
1201 * iface: Pointer to the IWineD3DDevice interface
1202 * window: Window to setup
1204 *****************************************************************************/
1205 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1208 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1209 * switch, do nothing
1211 if (!This->style && !This->exStyle) return;
1213 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1214 This, window, This->style, This->exStyle);
1216 SetWindowLongW(window, GWL_STYLE, This->style);
1217 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1219 /* Delete the old values */
1220 This->style = 0;
1221 This->exStyle = 0;
1223 /* Inform the window about the update */
1224 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1225 0, 0, 0, 0, /* Pos, Size, ignored */
1226 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1229 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1230 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1231 IUnknown* parent,
1232 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1233 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1236 HDC hDc;
1237 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1238 HRESULT hr = WINED3D_OK;
1239 IUnknown *bufferParent;
1240 Display *display;
1242 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1244 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1245 * does a device hold a reference to a swap chain giving them a lifetime of the device
1246 * or does the swap chain notify the device of its destruction.
1247 *******************************/
1249 /* Check the params */
1250 if(*pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1251 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1252 return WINED3DERR_INVALIDCALL;
1253 } else if (*pPresentationParameters->BackBufferCount > 1) {
1254 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");
1257 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1259 /*********************
1260 * Lookup the window Handle and the relating X window handle
1261 ********************/
1263 /* Setup hwnd we are using, plus which display this equates to */
1264 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1265 if (!object->win_handle) {
1266 object->win_handle = This->createParms.hFocusWindow;
1269 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1270 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1271 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1272 return WINED3DERR_NOTAVAILABLE;
1274 hDc = GetDC(object->win_handle);
1275 display = get_display(hDc);
1276 ReleaseDC(object->win_handle, hDc);
1277 TRACE("Using a display of %p %p\n", display, hDc);
1279 if (NULL == display || NULL == hDc) {
1280 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1281 return WINED3DERR_NOTAVAILABLE;
1284 if (object->win == 0) {
1285 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1286 return WINED3DERR_NOTAVAILABLE;
1289 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1290 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1292 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1293 * then the corresponding dimension of the client area of the hDeviceWindow
1294 * (or the focus window, if hDeviceWindow is NULL) is taken.
1295 **********************/
1297 if (*(pPresentationParameters->Windowed) &&
1298 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1299 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1301 RECT Rect;
1302 GetClientRect(object->win_handle, &Rect);
1304 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1305 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1306 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1308 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1309 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1310 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1314 /* Put the correct figures in the presentation parameters */
1315 TRACE("Copying across presentation parameters\n");
1316 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1317 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1318 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1319 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1320 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1321 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1322 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1323 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1324 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1325 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1326 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1327 object->presentParms.Flags = *(pPresentationParameters->Flags);
1328 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1329 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1331 TRACE("calling rendertarget CB\n");
1332 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1333 parent,
1334 object->presentParms.BackBufferWidth,
1335 object->presentParms.BackBufferHeight,
1336 object->presentParms.BackBufferFormat,
1337 object->presentParms.MultiSampleType,
1338 object->presentParms.MultiSampleQuality,
1339 TRUE /* Lockable */,
1340 &object->frontBuffer,
1341 NULL /* pShared (always null)*/);
1342 if (object->frontBuffer != NULL) {
1343 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1344 } else {
1345 ERR("Failed to create the front buffer\n");
1346 goto error;
1350 * Create an opengl context for the display visual
1351 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1352 * use different properties after that point in time. FIXME: How to handle when requested format
1353 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1354 * it chooses is identical to the one already being used!
1355 **********************************/
1357 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1358 ENTER_GL();
1359 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1360 LEAVE_GL();
1362 if (!object->context) {
1363 ERR("Failed to create a new context\n");
1364 hr = WINED3DERR_NOTAVAILABLE;
1365 goto error;
1366 } else {
1367 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1368 object->win_handle, object->context->glCtx, object->win);
1371 /*********************
1372 * Windowed / Fullscreen
1373 *******************/
1376 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1377 * so we should really check to see if there is a fullscreen swapchain already
1378 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1379 **************************************/
1381 if (!*(pPresentationParameters->Windowed)) {
1383 DEVMODEW devmode;
1384 HDC hdc;
1385 int bpp = 0;
1386 RECT clip_rc;
1388 /* Get info on the current display setup */
1389 hdc = GetDC(0);
1390 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1391 ReleaseDC(0, hdc);
1393 /* Change the display settings */
1394 memset(&devmode, 0, sizeof(DEVMODEW));
1395 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1396 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1397 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1398 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1399 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1400 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1402 /* For GetDisplayMode */
1403 This->ddraw_width = devmode.dmPelsWidth;
1404 This->ddraw_height = devmode.dmPelsHeight;
1405 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1407 IWineD3DDevice_SetFullscreen(iface, TRUE);
1409 /* And finally clip mouse to our screen */
1410 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1411 ClipCursor(&clip_rc);
1414 /*********************
1415 * Create the back, front and stencil buffers
1416 *******************/
1417 if(object->presentParms.BackBufferCount > 0) {
1418 int i;
1420 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1421 if(!object->backBuffer) {
1422 ERR("Out of memory\n");
1423 hr = E_OUTOFMEMORY;
1424 goto error;
1427 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1428 TRACE("calling rendertarget CB\n");
1429 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1430 parent,
1431 object->presentParms.BackBufferWidth,
1432 object->presentParms.BackBufferHeight,
1433 object->presentParms.BackBufferFormat,
1434 object->presentParms.MultiSampleType,
1435 object->presentParms.MultiSampleQuality,
1436 TRUE /* Lockable */,
1437 &object->backBuffer[i],
1438 NULL /* pShared (always null)*/);
1439 if(hr == WINED3D_OK && object->backBuffer[i]) {
1440 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1441 } else {
1442 ERR("Cannot create new back buffer\n");
1443 goto error;
1445 ENTER_GL();
1446 glDrawBuffer(GL_BACK);
1447 checkGLcall("glDrawBuffer(GL_BACK)");
1448 LEAVE_GL();
1450 } else {
1451 object->backBuffer = NULL;
1453 /* Single buffering - draw to front buffer */
1454 ENTER_GL();
1455 glDrawBuffer(GL_FRONT);
1456 checkGLcall("glDrawBuffer(GL_FRONT)");
1457 LEAVE_GL();
1460 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1461 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1462 TRACE("Creating depth stencil buffer\n");
1463 if (This->depthStencilBuffer == NULL ) {
1464 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1465 parent,
1466 object->presentParms.BackBufferWidth,
1467 object->presentParms.BackBufferHeight,
1468 object->presentParms.AutoDepthStencilFormat,
1469 object->presentParms.MultiSampleType,
1470 object->presentParms.MultiSampleQuality,
1471 FALSE /* FIXME: Discard */,
1472 &This->depthStencilBuffer,
1473 NULL /* pShared (always null)*/ );
1474 if (This->depthStencilBuffer != NULL)
1475 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1478 /** TODO: A check on width, height and multisample types
1479 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1480 ****************************/
1481 object->wantsDepthStencilBuffer = TRUE;
1482 } else {
1483 object->wantsDepthStencilBuffer = FALSE;
1486 TRACE("Created swapchain %p\n", object);
1487 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1488 return WINED3D_OK;
1490 error:
1491 if (object->backBuffer) {
1492 int i;
1493 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1494 if(object->backBuffer[i]) {
1495 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1496 IUnknown_Release(bufferParent); /* once for the get parent */
1497 if (IUnknown_Release(bufferParent) > 0) {
1498 FIXME("(%p) Something's still holding the back buffer\n",This);
1502 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1503 object->backBuffer = NULL;
1505 if(object->context) {
1506 DestroyContext(This, object->context);
1508 if(object->frontBuffer) {
1509 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1510 IUnknown_Release(bufferParent); /* once for the get parent */
1511 if (IUnknown_Release(bufferParent) > 0) {
1512 FIXME("(%p) Something's still holding the front buffer\n",This);
1515 if(object) HeapFree(GetProcessHeap(), 0, object);
1516 return hr;
1519 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1520 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1522 TRACE("(%p)\n", This);
1524 return This->NumberOfSwapChains;
1527 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1529 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1531 if(iSwapChain < This->NumberOfSwapChains) {
1532 *pSwapChain = This->swapchains[iSwapChain];
1533 IWineD3DSwapChain_AddRef(*pSwapChain);
1534 TRACE("(%p) returning %p\n", This, *pSwapChain);
1535 return WINED3D_OK;
1536 } else {
1537 TRACE("Swapchain out of range\n");
1538 *pSwapChain = NULL;
1539 return WINED3DERR_INVALIDCALL;
1543 /*****
1544 * Vertex Declaration
1545 *****/
1546 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1547 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1549 IWineD3DVertexDeclarationImpl *object = NULL;
1550 HRESULT hr = WINED3D_OK;
1552 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1553 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1555 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1556 object->allFVF = 0;
1558 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1560 return hr;
1563 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1566 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1567 HRESULT hr = WINED3D_OK;
1568 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1569 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1571 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1573 if (vertex_declaration) {
1574 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1577 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1579 if (WINED3D_OK != hr) {
1580 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1581 IWineD3DVertexShader_Release(*ppVertexShader);
1582 return WINED3DERR_INVALIDCALL;
1585 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
1586 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1587 /* Foo */
1588 } else {
1589 /* Bar */
1592 #endif
1594 return WINED3D_OK;
1597 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1599 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1600 HRESULT hr = WINED3D_OK;
1602 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1603 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1604 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1605 if (WINED3D_OK == hr) {
1606 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1607 } else {
1608 WARN("(%p) : Failed to create pixel shader\n", This);
1611 return hr;
1614 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1616 IWineD3DPaletteImpl *object;
1617 HRESULT hr;
1618 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1620 /* Create the new object */
1621 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1622 if(!object) {
1623 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1624 return E_OUTOFMEMORY;
1627 object->lpVtbl = &IWineD3DPalette_Vtbl;
1628 object->ref = 1;
1629 object->Flags = Flags;
1630 object->parent = Parent;
1631 object->wineD3DDevice = This;
1632 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1634 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1636 if(!object->hpal) {
1637 HeapFree( GetProcessHeap(), 0, object);
1638 return E_OUTOFMEMORY;
1641 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1642 if(FAILED(hr)) {
1643 IWineD3DPalette_Release((IWineD3DPalette *) object);
1644 return hr;
1647 *Palette = (IWineD3DPalette *) object;
1649 return WINED3D_OK;
1652 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1654 IWineD3DSwapChainImpl *swapchain;
1655 DWORD state;
1657 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1658 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1660 /* TODO: Test if OpenGL is compiled in and loaded */
1662 /* Initialize the texture unit mapping to a 1:1 mapping */
1663 for(state = 0; state < MAX_SAMPLERS; state++) {
1664 This->texUnitMap[state] = state;
1666 This->oneToOneTexUnitMap = TRUE;
1668 /* Setup the implicit swapchain */
1669 TRACE("Creating implicit swapchain\n");
1670 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
1671 WARN("Failed to create implicit swapchain\n");
1672 return WINED3DERR_INVALIDCALL;
1675 This->NumberOfSwapChains = 1;
1676 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1677 if(!This->swapchains) {
1678 ERR("Out of memory!\n");
1679 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1680 return E_OUTOFMEMORY;
1682 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1684 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1686 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1687 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1688 This->render_targets[0] = swapchain->backBuffer[0];
1689 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1691 else {
1692 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1693 This->render_targets[0] = swapchain->frontBuffer;
1694 This->lastActiveRenderTarget = swapchain->frontBuffer;
1696 IWineD3DSurface_AddRef(This->render_targets[0]);
1697 This->activeContext = swapchain->context;
1699 /* Depth Stencil support */
1700 This->stencilBufferTarget = This->depthStencilBuffer;
1701 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1702 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1704 if (NULL != This->stencilBufferTarget) {
1705 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1708 /* Set up some starting GL setup */
1709 ENTER_GL();
1711 * Initialize openGL extension related variables
1712 * with Default values
1715 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1716 /* Setup all the devices defaults */
1717 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1718 #if 0
1719 IWineD3DImpl_CheckGraphicsMemory();
1720 #endif
1722 /* Initialize our list of GLSL programs */
1723 list_init(&This->glsl_shader_progs);
1725 { /* Set a default viewport */
1726 WINED3DVIEWPORT vp;
1727 vp.X = 0;
1728 vp.Y = 0;
1729 vp.Width = *(pPresentationParameters->BackBufferWidth);
1730 vp.Height = *(pPresentationParameters->BackBufferHeight);
1731 vp.MinZ = 0.0f;
1732 vp.MaxZ = 1.0f;
1733 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1736 /* Initialize the current view state */
1737 This->view_ident = 1;
1738 This->contexts[0]->last_was_rhw = 0;
1739 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1740 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1741 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1742 LEAVE_GL();
1744 /* Clear the screen */
1745 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1747 This->d3d_initialized = TRUE;
1748 return WINED3D_OK;
1751 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1753 int sampler;
1754 uint i;
1755 TRACE("(%p)\n", This);
1757 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1759 /* Delete the pbuffer context if there is any */
1760 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1762 /* Delete the mouse cursor texture */
1763 if(This->cursorTexture) {
1764 ENTER_GL();
1765 glDeleteTextures(1, &This->cursorTexture);
1766 LEAVE_GL();
1767 This->cursorTexture = 0;
1770 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1771 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1774 /* Release the buffers (with sanity checks)*/
1775 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1776 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1777 if(This->depthStencilBuffer != This->stencilBufferTarget)
1778 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1780 This->stencilBufferTarget = NULL;
1782 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1783 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1784 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1786 TRACE("Setting rendertarget to NULL\n");
1787 This->render_targets[0] = NULL;
1789 if (This->depthStencilBuffer) {
1790 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1791 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1793 This->depthStencilBuffer = NULL;
1796 for(i=0; i < This->NumberOfSwapChains; i++) {
1797 TRACE("Releasing the implicit swapchain %d\n", i);
1798 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1799 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1803 HeapFree(GetProcessHeap(), 0, This->swapchains);
1804 This->swapchains = NULL;
1805 This->NumberOfSwapChains = 0;
1807 This->d3d_initialized = FALSE;
1808 return WINED3D_OK;
1811 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1813 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1815 /* Setup the window for fullscreen mode */
1816 if(fullscreen && !This->ddraw_fullscreen) {
1817 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1818 } else if(!fullscreen && This->ddraw_fullscreen) {
1819 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1822 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1823 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1824 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1825 * separately.
1827 This->ddraw_fullscreen = fullscreen;
1830 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
1831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1833 DEVMODEW DevModeW;
1834 int i;
1835 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
1837 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
1839 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
1840 /* Ignore some modes if a description was passed */
1841 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
1842 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
1843 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
1845 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
1847 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
1848 return D3D_OK;
1851 return D3D_OK;
1854 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1855 DEVMODEW devmode;
1856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1857 LONG ret;
1858 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1859 RECT clip_rc;
1861 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1863 /* Resize the screen even without a window:
1864 * The app could have unset it with SetCooperativeLevel, but not called
1865 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1866 * but we don't have any hwnd
1869 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1870 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1871 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1872 devmode.dmPelsWidth = pMode->Width;
1873 devmode.dmPelsHeight = pMode->Height;
1875 devmode.dmDisplayFrequency = pMode->RefreshRate;
1876 if (pMode->RefreshRate != 0) {
1877 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1880 /* Only change the mode if necessary */
1881 if( (This->ddraw_width == pMode->Width) &&
1882 (This->ddraw_height == pMode->Height) &&
1883 (This->ddraw_format == pMode->Format) &&
1884 (pMode->RefreshRate == 0) ) {
1885 return D3D_OK;
1888 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1889 if (ret != DISP_CHANGE_SUCCESSFUL) {
1890 if(devmode.dmDisplayFrequency != 0) {
1891 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1892 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1893 devmode.dmDisplayFrequency = 0;
1894 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1896 if(ret != DISP_CHANGE_SUCCESSFUL) {
1897 return DDERR_INVALIDMODE;
1901 /* Store the new values */
1902 This->ddraw_width = pMode->Width;
1903 This->ddraw_height = pMode->Height;
1904 This->ddraw_format = pMode->Format;
1906 /* Only do this with a window of course */
1907 if(This->ddraw_window)
1908 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1910 /* And finally clip mouse to our screen */
1911 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1912 ClipCursor(&clip_rc);
1914 return WINED3D_OK;
1917 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1919 *ppD3D= This->wineD3D;
1920 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1921 IWineD3D_AddRef(*ppD3D);
1922 return WINED3D_OK;
1925 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1926 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1927 * into the video ram as possible and seeing how many fit
1928 * you can also get the correct initial value from nvidia and ATI's driver via X
1929 * texture memory is video memory + AGP memory
1930 *******************/
1931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1932 static BOOL showfixmes = TRUE;
1933 if (showfixmes) {
1934 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1935 (wined3d_settings.emulated_textureram/(1024*1024)),
1936 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1937 showfixmes = FALSE;
1939 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1940 (wined3d_settings.emulated_textureram/(1024*1024)),
1941 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1942 /* return simulated texture memory left */
1943 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1948 /*****
1949 * Get / Set FVF
1950 *****/
1951 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1954 /* Update the current state block */
1955 This->updateStateBlock->changed.fvf = TRUE;
1956 This->updateStateBlock->set.fvf = TRUE;
1958 if(This->updateStateBlock->fvf == fvf) {
1959 TRACE("Application is setting the old fvf over, nothing to do\n");
1960 return WINED3D_OK;
1963 This->updateStateBlock->fvf = fvf;
1964 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1966 return WINED3D_OK;
1970 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1972 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1973 *pfvf = This->stateBlock->fvf;
1974 return WINED3D_OK;
1977 /*****
1978 * Get / Set Stream Source
1979 *****/
1980 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1982 IWineD3DVertexBuffer *oldSrc;
1984 if (StreamNumber >= MAX_STREAMS) {
1985 WARN("Stream out of range %d\n", StreamNumber);
1986 return WINED3DERR_INVALIDCALL;
1989 oldSrc = This->stateBlock->streamSource[StreamNumber];
1990 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1992 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1993 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1995 if(oldSrc == pStreamData &&
1996 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1997 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1998 TRACE("Application is setting the old values over, nothing to do\n");
1999 return WINED3D_OK;
2002 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2003 if (pStreamData) {
2004 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2005 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2008 /* Handle recording of state blocks */
2009 if (This->isRecordingState) {
2010 TRACE("Recording... not performing anything\n");
2011 return WINED3D_OK;
2014 /* Need to do a getParent and pass the reffs up */
2015 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2016 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2017 so for now, just count internally */
2018 if (pStreamData != NULL) {
2019 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2020 InterlockedIncrement(&vbImpl->bindCount);
2022 if (oldSrc != NULL) {
2023 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2028 return WINED3D_OK;
2031 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2033 UINT streamFlags;
2035 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2036 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2039 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2040 if (streamFlags) {
2041 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2042 FIXME("stream index data not supported\n");
2044 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2045 FIXME("stream instance data not supported\n");
2049 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2051 if (StreamNumber >= MAX_STREAMS) {
2052 WARN("Stream out of range %d\n", StreamNumber);
2053 return WINED3DERR_INVALIDCALL;
2055 *pStream = This->stateBlock->streamSource[StreamNumber];
2056 *pStride = This->stateBlock->streamStride[StreamNumber];
2057 if (pOffset) {
2058 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2061 if (*pStream != NULL) {
2062 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2064 return WINED3D_OK;
2067 /*Should be quite easy, just an extension of vertexdata
2068 ref...
2069 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2071 The divider is a bit odd though
2073 VertexOffset = StartVertex / Divider * StreamStride +
2074 VertexIndex / Divider * StreamStride + StreamOffset
2077 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2080 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2082 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2083 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2085 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2086 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2087 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2089 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2090 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2094 return WINED3D_OK;
2097 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2100 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2101 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2103 TRACE("(%p) : returning %d\n", This, *Divider);
2105 return WINED3D_OK;
2108 /*****
2109 * Get / Set & Multiply Transform
2110 *****/
2111 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 /* Most of this routine, comments included copied from ddraw tree initially: */
2115 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2117 /* Handle recording of state blocks */
2118 if (This->isRecordingState) {
2119 TRACE("Recording... not performing anything\n");
2120 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2121 This->updateStateBlock->set.transform[d3dts] = TRUE;
2122 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2123 return WINED3D_OK;
2127 * If the new matrix is the same as the current one,
2128 * we cut off any further processing. this seems to be a reasonable
2129 * optimization because as was noticed, some apps (warcraft3 for example)
2130 * tend towards setting the same matrix repeatedly for some reason.
2132 * From here on we assume that the new matrix is different, wherever it matters.
2134 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2135 TRACE("The app is setting the same matrix over again\n");
2136 return WINED3D_OK;
2137 } else {
2138 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2142 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2143 where ViewMat = Camera space, WorldMat = world space.
2145 In OpenGL, camera and world space is combined into GL_MODELVIEW
2146 matrix. The Projection matrix stay projection matrix.
2149 /* Capture the times we can just ignore the change for now */
2150 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2151 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2152 /* Handled by the state manager */
2155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2156 return WINED3D_OK;
2159 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2161 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2162 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2163 return WINED3D_OK;
2166 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2167 WINED3DMATRIX *mat = NULL;
2168 WINED3DMATRIX temp;
2170 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2171 * below means it will be recorded in a state block change, but it
2172 * works regardless where it is recorded.
2173 * If this is found to be wrong, change to StateBlock.
2175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2176 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2178 if (State < HIGHEST_TRANSFORMSTATE)
2180 mat = &This->updateStateBlock->transforms[State];
2181 } else {
2182 FIXME("Unhandled transform state!!\n");
2185 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2187 /* Apply change via set transform - will reapply to eg. lights this way */
2188 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2191 /*****
2192 * Get / Set Light
2193 *****/
2194 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2195 you can reference any indexes you want as long as that number max are enabled at any
2196 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2197 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2198 but when recording, just build a chain pretty much of commands to be replayed. */
2200 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2201 float rho;
2202 PLIGHTINFOEL *object = NULL;
2203 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2204 struct list *e;
2206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2207 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2209 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2210 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2211 if(object->OriginalIndex == Index) break;
2212 object = NULL;
2215 if(!object) {
2216 TRACE("Adding new light\n");
2217 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2218 if(!object) {
2219 ERR("Out of memory error when allocating a light\n");
2220 return E_OUTOFMEMORY;
2222 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2223 object->glIndex = -1;
2224 object->OriginalIndex = Index;
2225 object->changed = TRUE;
2228 /* Initialize the object */
2229 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,
2230 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2231 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2232 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2233 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2234 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2235 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2237 /* Save away the information */
2238 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2240 switch (pLight->Type) {
2241 case WINED3DLIGHT_POINT:
2242 /* Position */
2243 object->lightPosn[0] = pLight->Position.x;
2244 object->lightPosn[1] = pLight->Position.y;
2245 object->lightPosn[2] = pLight->Position.z;
2246 object->lightPosn[3] = 1.0f;
2247 object->cutoff = 180.0f;
2248 /* FIXME: Range */
2249 break;
2251 case WINED3DLIGHT_DIRECTIONAL:
2252 /* Direction */
2253 object->lightPosn[0] = -pLight->Direction.x;
2254 object->lightPosn[1] = -pLight->Direction.y;
2255 object->lightPosn[2] = -pLight->Direction.z;
2256 object->lightPosn[3] = 0.0;
2257 object->exponent = 0.0f;
2258 object->cutoff = 180.0f;
2259 break;
2261 case WINED3DLIGHT_SPOT:
2262 /* Position */
2263 object->lightPosn[0] = pLight->Position.x;
2264 object->lightPosn[1] = pLight->Position.y;
2265 object->lightPosn[2] = pLight->Position.z;
2266 object->lightPosn[3] = 1.0;
2268 /* Direction */
2269 object->lightDirn[0] = pLight->Direction.x;
2270 object->lightDirn[1] = pLight->Direction.y;
2271 object->lightDirn[2] = pLight->Direction.z;
2272 object->lightDirn[3] = 1.0;
2275 * opengl-ish and d3d-ish spot lights use too different models for the
2276 * light "intensity" as a function of the angle towards the main light direction,
2277 * so we only can approximate very roughly.
2278 * however spot lights are rather rarely used in games (if ever used at all).
2279 * furthermore if still used, probably nobody pays attention to such details.
2281 if (pLight->Falloff == 0) {
2282 rho = 6.28f;
2283 } else {
2284 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2286 if (rho < 0.0001) rho = 0.0001f;
2287 object->exponent = -0.3/log(cos(rho/2));
2288 if (object->exponent > 128.0) {
2289 object->exponent = 128.0;
2291 object->cutoff = pLight->Phi*90/M_PI;
2293 /* FIXME: Range */
2294 break;
2296 default:
2297 FIXME("Unrecognized light type %d\n", pLight->Type);
2300 /* Update the live definitions if the light is currently assigned a glIndex */
2301 if (object->glIndex != -1 && !This->isRecordingState) {
2302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2304 return WINED3D_OK;
2307 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2308 PLIGHTINFOEL *lightInfo = NULL;
2309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2310 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2311 struct list *e;
2312 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2314 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2315 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2316 if(lightInfo->OriginalIndex == Index) break;
2317 lightInfo = NULL;
2320 if (lightInfo == NULL) {
2321 TRACE("Light information requested but light not defined\n");
2322 return WINED3DERR_INVALIDCALL;
2325 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2326 return WINED3D_OK;
2329 /*****
2330 * Get / Set Light Enable
2331 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2332 *****/
2333 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2334 PLIGHTINFOEL *lightInfo = NULL;
2335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2336 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2337 struct list *e;
2338 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2340 /* Tests show true = 128...not clear why */
2341 Enable = Enable? 128: 0;
2343 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2344 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2345 if(lightInfo->OriginalIndex == Index) break;
2346 lightInfo = NULL;
2348 TRACE("Found light: %p\n", lightInfo);
2350 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2351 if (lightInfo == NULL) {
2353 TRACE("Light enabled requested but light not defined, so defining one!\n");
2354 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2356 /* Search for it again! Should be fairly quick as near head of list */
2357 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2358 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2359 if(lightInfo->OriginalIndex == Index) break;
2360 lightInfo = NULL;
2362 if (lightInfo == NULL) {
2363 FIXME("Adding default lights has failed dismally\n");
2364 return WINED3DERR_INVALIDCALL;
2368 lightInfo->enabledChanged = TRUE;
2369 if(!Enable) {
2370 if(lightInfo->glIndex != -1) {
2371 if(!This->isRecordingState) {
2372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2375 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2376 lightInfo->glIndex = -1;
2377 } else {
2378 TRACE("Light already disabled, nothing to do\n");
2380 } else {
2381 if (lightInfo->glIndex != -1) {
2382 /* nop */
2383 TRACE("Nothing to do as light was enabled\n");
2384 } else {
2385 int i;
2386 /* Find a free gl light */
2387 for(i = 0; i < This->maxConcurrentLights; i++) {
2388 if(This->stateBlock->activeLights[i] == NULL) {
2389 This->stateBlock->activeLights[i] = lightInfo;
2390 lightInfo->glIndex = i;
2391 break;
2394 if(lightInfo->glIndex == -1) {
2395 ERR("Too many concurrently active lights\n");
2396 return WINED3DERR_INVALIDCALL;
2399 /* i == lightInfo->glIndex */
2400 if(!This->isRecordingState) {
2401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2406 return WINED3D_OK;
2409 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2411 PLIGHTINFOEL *lightInfo = NULL;
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413 struct list *e;
2414 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2415 TRACE("(%p) : for idx(%d)\n", This, Index);
2417 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2418 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2419 if(lightInfo->OriginalIndex == Index) break;
2420 lightInfo = NULL;
2423 if (lightInfo == NULL) {
2424 TRACE("Light enabled state requested but light not defined\n");
2425 return WINED3DERR_INVALIDCALL;
2427 /* true is 128 according to SetLightEnable */
2428 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2429 return WINED3D_OK;
2432 /*****
2433 * Get / Set Clip Planes
2434 *****/
2435 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2437 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2439 /* Validate Index */
2440 if (Index >= GL_LIMITS(clipplanes)) {
2441 TRACE("Application has requested clipplane this device doesn't support\n");
2442 return WINED3DERR_INVALIDCALL;
2445 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2446 This->updateStateBlock->set.clipplane[Index] = TRUE;
2447 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2448 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2449 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2450 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2452 /* Handle recording of state blocks */
2453 if (This->isRecordingState) {
2454 TRACE("Recording... not performing anything\n");
2455 return WINED3D_OK;
2458 /* Apply it */
2460 ENTER_GL();
2462 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2463 glMatrixMode(GL_MODELVIEW);
2464 glPushMatrix();
2465 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2467 TRACE("Clipplane [%f,%f,%f,%f]\n",
2468 This->updateStateBlock->clipplane[Index][0],
2469 This->updateStateBlock->clipplane[Index][1],
2470 This->updateStateBlock->clipplane[Index][2],
2471 This->updateStateBlock->clipplane[Index][3]);
2472 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2473 checkGLcall("glClipPlane");
2475 glPopMatrix();
2476 LEAVE_GL();
2478 return WINED3D_OK;
2481 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 TRACE("(%p) : for idx %d\n", This, Index);
2485 /* Validate Index */
2486 if (Index >= GL_LIMITS(clipplanes)) {
2487 TRACE("Application has requested clipplane this device doesn't support\n");
2488 return WINED3DERR_INVALIDCALL;
2491 pPlane[0] = This->stateBlock->clipplane[Index][0];
2492 pPlane[1] = This->stateBlock->clipplane[Index][1];
2493 pPlane[2] = This->stateBlock->clipplane[Index][2];
2494 pPlane[3] = This->stateBlock->clipplane[Index][3];
2495 return WINED3D_OK;
2498 /*****
2499 * Get / Set Clip Plane Status
2500 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2501 *****/
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 FIXME("(%p) : stub\n", This);
2505 if (NULL == pClipStatus) {
2506 return WINED3DERR_INVALIDCALL;
2508 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2509 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2510 return WINED3D_OK;
2513 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2515 FIXME("(%p) : stub\n", This);
2516 if (NULL == pClipStatus) {
2517 return WINED3DERR_INVALIDCALL;
2519 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2520 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2521 return WINED3D_OK;
2524 /*****
2525 * Get / Set Material
2526 *****/
2527 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 This->updateStateBlock->changed.material = TRUE;
2531 This->updateStateBlock->set.material = TRUE;
2532 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2534 /* Handle recording of state blocks */
2535 if (This->isRecordingState) {
2536 TRACE("Recording... not performing anything\n");
2537 return WINED3D_OK;
2540 ENTER_GL();
2541 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2542 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2543 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2544 pMaterial->Ambient.b, pMaterial->Ambient.a);
2545 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2546 pMaterial->Specular.b, pMaterial->Specular.a);
2547 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2548 pMaterial->Emissive.b, pMaterial->Emissive.a);
2549 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2551 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2552 checkGLcall("glMaterialfv(GL_AMBIENT)");
2553 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2554 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2556 /* Only change material color if specular is enabled, otherwise it is set to black */
2557 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2558 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2559 checkGLcall("glMaterialfv(GL_SPECULAR");
2560 } else {
2561 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2562 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2563 checkGLcall("glMaterialfv(GL_SPECULAR");
2565 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2566 checkGLcall("glMaterialfv(GL_EMISSION)");
2567 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2568 checkGLcall("glMaterialf(GL_SHININESS");
2570 LEAVE_GL();
2571 return WINED3D_OK;
2574 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2576 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2577 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2578 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2579 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2580 pMaterial->Ambient.b, pMaterial->Ambient.a);
2581 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2582 pMaterial->Specular.b, pMaterial->Specular.a);
2583 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2584 pMaterial->Emissive.b, pMaterial->Emissive.a);
2585 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2587 return WINED3D_OK;
2590 /*****
2591 * Get / Set Indices
2592 *****/
2593 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2594 UINT BaseVertexIndex) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2596 IWineD3DIndexBuffer *oldIdxs;
2597 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2599 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2600 oldIdxs = This->updateStateBlock->pIndexData;
2602 This->updateStateBlock->changed.indices = TRUE;
2603 This->updateStateBlock->set.indices = TRUE;
2604 This->updateStateBlock->pIndexData = pIndexData;
2605 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2607 /* Handle recording of state blocks */
2608 if (This->isRecordingState) {
2609 TRACE("Recording... not performing anything\n");
2610 return WINED3D_OK;
2613 /* So far only the base vertex index is tracked */
2614 if(BaseVertexIndex != oldBaseIndex) {
2615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2617 return WINED3D_OK;
2620 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2623 *ppIndexData = This->stateBlock->pIndexData;
2625 /* up ref count on ppindexdata */
2626 if (*ppIndexData) {
2627 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2628 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2629 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2630 }else{
2631 TRACE("(%p) No index data set\n", This);
2633 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2635 return WINED3D_OK;
2638 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2639 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 TRACE("(%p)->(%d)\n", This, BaseIndex);
2643 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2644 TRACE("Application is setting the old value over, nothing to do\n");
2645 return WINED3D_OK;
2648 This->updateStateBlock->baseVertexIndex = BaseIndex;
2650 if (This->isRecordingState) {
2651 TRACE("Recording... not performing anything\n");
2652 return WINED3D_OK;
2654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2655 return WINED3D_OK;
2658 /*****
2659 * Get / Set Viewports
2660 *****/
2661 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 TRACE("(%p)\n", This);
2665 This->updateStateBlock->changed.viewport = TRUE;
2666 This->updateStateBlock->set.viewport = TRUE;
2667 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2669 /* Handle recording of state blocks */
2670 if (This->isRecordingState) {
2671 TRACE("Recording... not performing anything\n");
2672 return WINED3D_OK;
2675 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2676 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2679 return WINED3D_OK;
2683 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2685 TRACE("(%p)\n", This);
2686 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2687 return WINED3D_OK;
2690 /*****
2691 * Get / Set Render States
2692 * TODO: Verify against dx9 definitions
2693 *****/
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 DWORD oldValue = This->stateBlock->renderState[State];
2699 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2701 This->updateStateBlock->changed.renderState[State] = TRUE;
2702 This->updateStateBlock->set.renderState[State] = TRUE;
2703 This->updateStateBlock->renderState[State] = Value;
2705 /* Handle recording of state blocks */
2706 if (This->isRecordingState) {
2707 TRACE("Recording... not performing anything\n");
2708 return WINED3D_OK;
2711 /* Compared here and not before the assignment to allow proper stateblock recording */
2712 if(Value == oldValue) {
2713 TRACE("Application is setting the old value over, nothing to do\n");
2714 } else {
2715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2718 return WINED3D_OK;
2721 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2724 *pValue = This->stateBlock->renderState[State];
2725 return WINED3D_OK;
2728 /*****
2729 * Get / Set Sampler States
2730 * TODO: Verify against dx9 definitions
2731 *****/
2733 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2738 * SetSampler is designed to allow for more than the standard up to 8 textures
2739 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2740 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2742 * http://developer.nvidia.com/object/General_FAQ.html#t6
2744 * There are two new settings for GForce
2745 * the sampler one:
2746 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2747 * and the texture one:
2748 * GL_MAX_TEXTURE_COORDS_ARB.
2749 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2750 ******************/
2751 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2752 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
2753 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2754 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
2755 return WINED3DERR_INVALIDCALL;
2758 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2759 debug_d3dsamplerstate(Type), Type, Value);
2760 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2761 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2762 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2764 /* Handle recording of state blocks */
2765 if (This->isRecordingState) {
2766 TRACE("Recording... not performing anything\n");
2767 return WINED3D_OK;
2770 if(oldValue == Value) {
2771 TRACE("Application is setting the old value over, nothing to do\n");
2772 return WINED3D_OK;
2775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2777 return WINED3D_OK;
2780 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 /** TODO: check that sampler is in range **/
2783 *Value = This->stateBlock->samplerState[Sampler][Type];
2784 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2786 return WINED3D_OK;
2789 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2791 RECT windowRect;
2792 UINT winHeight;
2794 This->updateStateBlock->set.scissorRect = TRUE;
2795 This->updateStateBlock->changed.scissorRect = TRUE;
2796 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2798 if(This->isRecordingState) {
2799 TRACE("Recording... not performing anything\n");
2800 return WINED3D_OK;
2803 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
2804 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2805 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2807 winHeight = windowRect.bottom - windowRect.top;
2808 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
2809 pRect->right - pRect->left, pRect->bottom - pRect->top);
2810 ENTER_GL();
2811 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
2812 checkGLcall("glScissor");
2813 LEAVE_GL();
2815 return WINED3D_OK;
2818 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2821 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2822 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2823 return WINED3D_OK;
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2828 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2830 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2832 This->updateStateBlock->vertexDecl = pDecl;
2833 This->updateStateBlock->changed.vertexDecl = TRUE;
2834 This->updateStateBlock->set.vertexDecl = TRUE;
2836 if (This->isRecordingState) {
2837 TRACE("Recording... not performing anything\n");
2838 return WINED3D_OK;
2839 } else if(pDecl == oldDecl) {
2840 /* Checked after the assignment to allow proper stateblock recording */
2841 TRACE("Application is setting the old declaration over, nothing to do\n");
2842 return WINED3D_OK;
2845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2846 return WINED3D_OK;
2849 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2854 *ppDecl = This->stateBlock->vertexDecl;
2855 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2856 return WINED3D_OK;
2859 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2861 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2863 This->updateStateBlock->vertexShader = pShader;
2864 This->updateStateBlock->changed.vertexShader = TRUE;
2865 This->updateStateBlock->set.vertexShader = TRUE;
2867 if (This->isRecordingState) {
2868 TRACE("Recording... not performing anything\n");
2869 return WINED3D_OK;
2870 } else if(oldShader == pShader) {
2871 /* Checked here to allow proper stateblock recording */
2872 TRACE("App is setting the old shader over, nothing to do\n");
2873 return WINED3D_OK;
2876 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2880 return WINED3D_OK;
2883 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 if (NULL == ppShader) {
2887 return WINED3DERR_INVALIDCALL;
2889 *ppShader = This->stateBlock->vertexShader;
2890 if( NULL != *ppShader)
2891 IWineD3DVertexShader_AddRef(*ppShader);
2893 TRACE("(%p) : returning %p\n", This, *ppShader);
2894 return WINED3D_OK;
2897 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2898 IWineD3DDevice *iface,
2899 UINT start,
2900 CONST BOOL *srcData,
2901 UINT count) {
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 int i, cnt = min(count, MAX_CONST_B - start);
2906 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2907 iface, srcData, start, count);
2909 if (srcData == NULL || cnt < 0)
2910 return WINED3DERR_INVALIDCALL;
2912 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2913 for (i = 0; i < cnt; i++)
2914 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2916 for (i = start; i < cnt + start; ++i) {
2917 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2918 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2923 return WINED3D_OK;
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2927 IWineD3DDevice *iface,
2928 UINT start,
2929 BOOL *dstData,
2930 UINT count) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2933 int cnt = min(count, MAX_CONST_B - start);
2935 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2936 iface, dstData, start, count);
2938 if (dstData == NULL || cnt < 0)
2939 return WINED3DERR_INVALIDCALL;
2941 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2942 return WINED3D_OK;
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2946 IWineD3DDevice *iface,
2947 UINT start,
2948 CONST int *srcData,
2949 UINT count) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 int i, cnt = min(count, MAX_CONST_I - start);
2954 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2955 iface, srcData, start, count);
2957 if (srcData == NULL || cnt < 0)
2958 return WINED3DERR_INVALIDCALL;
2960 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2961 for (i = 0; i < cnt; i++)
2962 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2963 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2965 for (i = start; i < cnt + start; ++i) {
2966 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2967 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2972 return WINED3D_OK;
2975 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2976 IWineD3DDevice *iface,
2977 UINT start,
2978 int *dstData,
2979 UINT count) {
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 int cnt = min(count, MAX_CONST_I - start);
2984 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2985 iface, dstData, start, count);
2987 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2988 return WINED3DERR_INVALIDCALL;
2990 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2991 return WINED3D_OK;
2994 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2995 IWineD3DDevice *iface,
2996 UINT start,
2997 CONST float *srcData,
2998 UINT count) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3003 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3004 iface, srcData, start, count);
3006 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3007 return WINED3DERR_INVALIDCALL;
3009 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3010 for (i = 0; i < cnt; i++)
3011 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3012 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3014 for (i = start; i < cnt + start; ++i) {
3015 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3016 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3017 ptr->idx = i;
3018 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3019 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3021 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3026 return WINED3D_OK;
3029 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3030 IWineD3DDevice *iface,
3031 UINT start,
3032 float *dstData,
3033 UINT count) {
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3038 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3039 iface, dstData, start, count);
3041 if (dstData == NULL || cnt < 0)
3042 return WINED3DERR_INVALIDCALL;
3044 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3045 return WINED3D_OK;
3048 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3049 DWORD i;
3050 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3055 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3056 DWORD i, tex;
3057 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3058 * it is never called.
3060 * Rules are:
3061 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3062 * that would be really messy and require shader recompilation
3063 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3064 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3065 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3066 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3068 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3069 if(This->oneToOneTexUnitMap) {
3070 TRACE("Not touching 1:1 map\n");
3071 return;
3073 TRACE("Restoring 1:1 texture unit mapping\n");
3074 /* Restore a 1:1 mapping */
3075 for(i = 0; i < MAX_SAMPLERS; i++) {
3076 if(This->texUnitMap[i] != i) {
3077 This->texUnitMap[i] = i;
3078 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3079 markTextureStagesDirty(This, i);
3082 This->oneToOneTexUnitMap = TRUE;
3083 return;
3084 } else {
3085 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3086 * First, see if we can succeed at all
3088 tex = 0;
3089 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3090 if(This->stateBlock->textures[i] == NULL) tex++;
3093 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3094 FIXME("Too many bound textures to support the combiner settings\n");
3095 return;
3098 /* Now work out the mapping */
3099 tex = 0;
3100 This->oneToOneTexUnitMap = FALSE;
3101 WARN("Non 1:1 mapping UNTESTED!\n");
3102 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3103 /* Skip NULL textures */
3104 if (!This->stateBlock->textures[i]) {
3105 /* Map to -1, so the check below doesn't fail if a non-NULL
3106 * texture is set on this stage */
3107 TRACE("Mapping texture stage %d to -1\n", i);
3108 This->texUnitMap[i] = -1;
3110 continue;
3113 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3114 if(This->texUnitMap[i] != tex) {
3115 This->texUnitMap[i] = tex;
3116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3117 markTextureStagesDirty(This, i);
3120 ++tex;
3125 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3128 This->updateStateBlock->pixelShader = pShader;
3129 This->updateStateBlock->changed.pixelShader = TRUE;
3130 This->updateStateBlock->set.pixelShader = TRUE;
3132 /* Handle recording of state blocks */
3133 if (This->isRecordingState) {
3134 TRACE("Recording... not performing anything\n");
3137 if (This->isRecordingState) {
3138 TRACE("Recording... not performing anything\n");
3139 return WINED3D_OK;
3142 if(pShader == oldShader) {
3143 TRACE("App is setting the old pixel shader over, nothing to do\n");
3144 return WINED3D_OK;
3147 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3150 /* Rebuild the texture unit mapping if nvrc's are supported */
3151 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3152 IWineD3DDeviceImpl_FindTexUnitMap(This);
3155 return WINED3D_OK;
3158 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 if (NULL == ppShader) {
3162 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3163 return WINED3DERR_INVALIDCALL;
3166 *ppShader = This->stateBlock->pixelShader;
3167 if (NULL != *ppShader) {
3168 IWineD3DPixelShader_AddRef(*ppShader);
3170 TRACE("(%p) : returning %p\n", This, *ppShader);
3171 return WINED3D_OK;
3174 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3175 IWineD3DDevice *iface,
3176 UINT start,
3177 CONST BOOL *srcData,
3178 UINT count) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 int i, cnt = min(count, MAX_CONST_B - start);
3183 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3184 iface, srcData, start, count);
3186 if (srcData == NULL || cnt < 0)
3187 return WINED3DERR_INVALIDCALL;
3189 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3190 for (i = 0; i < cnt; i++)
3191 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3193 for (i = start; i < cnt + start; ++i) {
3194 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3195 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3200 return WINED3D_OK;
3203 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3204 IWineD3DDevice *iface,
3205 UINT start,
3206 BOOL *dstData,
3207 UINT count) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 int cnt = min(count, MAX_CONST_B - start);
3212 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3213 iface, dstData, start, count);
3215 if (dstData == NULL || cnt < 0)
3216 return WINED3DERR_INVALIDCALL;
3218 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3219 return WINED3D_OK;
3222 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3223 IWineD3DDevice *iface,
3224 UINT start,
3225 CONST int *srcData,
3226 UINT count) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 int i, cnt = min(count, MAX_CONST_I - start);
3231 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3232 iface, srcData, start, count);
3234 if (srcData == NULL || cnt < 0)
3235 return WINED3DERR_INVALIDCALL;
3237 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3238 for (i = 0; i < cnt; i++)
3239 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3240 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3242 for (i = start; i < cnt + start; ++i) {
3243 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3244 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3249 return WINED3D_OK;
3252 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3253 IWineD3DDevice *iface,
3254 UINT start,
3255 int *dstData,
3256 UINT count) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 int cnt = min(count, MAX_CONST_I - start);
3261 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3262 iface, dstData, start, count);
3264 if (dstData == NULL || cnt < 0)
3265 return WINED3DERR_INVALIDCALL;
3267 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3268 return WINED3D_OK;
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3272 IWineD3DDevice *iface,
3273 UINT start,
3274 CONST float *srcData,
3275 UINT count) {
3277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3278 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3280 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3281 iface, srcData, start, count);
3283 if (srcData == NULL || cnt < 0)
3284 return WINED3DERR_INVALIDCALL;
3286 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3287 for (i = 0; i < cnt; i++)
3288 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3289 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3291 for (i = start; i < cnt + start; ++i) {
3292 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3293 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3294 ptr->idx = i;
3295 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3296 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3298 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3303 return WINED3D_OK;
3306 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3307 IWineD3DDevice *iface,
3308 UINT start,
3309 float *dstData,
3310 UINT count) {
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3313 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3315 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3316 iface, dstData, start, count);
3318 if (dstData == NULL || cnt < 0)
3319 return WINED3DERR_INVALIDCALL;
3321 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3322 return WINED3D_OK;
3325 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3326 static HRESULT
3327 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3328 char *dest_ptr, *dest_conv = NULL;
3329 unsigned int i;
3330 DWORD DestFVF = dest->fvf;
3331 WINED3DVIEWPORT vp;
3332 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3333 BOOL doClip;
3334 int numTextures;
3336 if (SrcFVF & WINED3DFVF_NORMAL) {
3337 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3340 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3341 ERR("Source has no position mask\n");
3342 return WINED3DERR_INVALIDCALL;
3345 /* We might access VBOs from this code, so hold the lock */
3346 ENTER_GL();
3348 if (dest->resource.allocatedMemory == NULL) {
3349 /* This may happen if we do direct locking into a vbo. Unlikely,
3350 * but theoretically possible(ddraw processvertices test)
3352 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3353 if(!dest->resource.allocatedMemory) {
3354 LEAVE_GL();
3355 ERR("Out of memory\n");
3356 return E_OUTOFMEMORY;
3358 if(dest->vbo) {
3359 void *src;
3360 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3361 checkGLcall("glBindBufferARB");
3362 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3363 if(src) {
3364 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3366 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3367 checkGLcall("glUnmapBufferARB");
3371 /* Get a pointer into the destination vbo(create one if none exists) and
3372 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3374 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3375 CreateVBO(dest);
3378 if(dest->vbo) {
3379 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3380 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3381 if(!dest_conv) {
3382 ERR("glMapBuffer failed\n");
3383 /* Continue without storing converted vertices */
3387 /* Should I clip?
3388 * a) WINED3DRS_CLIPPING is enabled
3389 * b) WINED3DVOP_CLIP is passed
3391 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3392 static BOOL warned = FALSE;
3394 * The clipping code is not quite correct. Some things need
3395 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3396 * so disable clipping for now.
3397 * (The graphics in Half-Life are broken, and my processvertices
3398 * test crashes with IDirect3DDevice3)
3399 doClip = TRUE;
3401 doClip = FALSE;
3402 if(!warned) {
3403 warned = TRUE;
3404 FIXME("Clipping is broken and disabled for now\n");
3406 } else doClip = FALSE;
3407 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3408 if(dest_conv) {
3409 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3412 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3413 WINED3DTS_VIEW,
3414 &view_mat);
3415 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3416 WINED3DTS_PROJECTION,
3417 &proj_mat);
3418 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3419 WINED3DTS_WORLDMATRIX(0),
3420 &world_mat);
3422 TRACE("View mat:\n");
3423 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);
3424 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);
3425 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);
3426 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);
3428 TRACE("Proj mat:\n");
3429 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);
3430 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);
3431 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);
3432 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);
3434 TRACE("World mat:\n");
3435 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);
3436 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);
3437 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);
3438 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);
3440 /* Get the viewport */
3441 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3442 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3443 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3445 multiply_matrix(&mat,&view_mat,&world_mat);
3446 multiply_matrix(&mat,&proj_mat,&mat);
3448 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3450 for (i = 0; i < dwCount; i+= 1) {
3451 unsigned int tex_index;
3453 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3454 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3455 /* The position first */
3456 float *p =
3457 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3458 float x, y, z, rhw;
3459 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3461 /* Multiplication with world, view and projection matrix */
3462 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);
3463 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);
3464 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);
3465 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);
3467 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3469 /* WARNING: The following things are taken from d3d7 and were not yet checked
3470 * against d3d8 or d3d9!
3473 /* Clipping conditions: From
3474 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3476 * A vertex is clipped if it does not match the following requirements
3477 * -rhw < x <= rhw
3478 * -rhw < y <= rhw
3479 * 0 < z <= rhw
3480 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3482 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3483 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3487 if( !doClip ||
3488 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3489 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3490 ( rhw > eps ) ) ) {
3492 /* "Normal" viewport transformation (not clipped)
3493 * 1) The values are divided by rhw
3494 * 2) The y axis is negative, so multiply it with -1
3495 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3496 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3497 * 4) Multiply x with Width/2 and add Width/2
3498 * 5) The same for the height
3499 * 6) Add the viewpoint X and Y to the 2D coordinates and
3500 * The minimum Z value to z
3501 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3503 * Well, basically it's simply a linear transformation into viewport
3504 * coordinates
3507 x /= rhw;
3508 y /= rhw;
3509 z /= rhw;
3511 y *= -1;
3513 x *= vp.Width / 2;
3514 y *= vp.Height / 2;
3515 z *= vp.MaxZ - vp.MinZ;
3517 x += vp.Width / 2 + vp.X;
3518 y += vp.Height / 2 + vp.Y;
3519 z += vp.MinZ;
3521 rhw = 1 / rhw;
3522 } else {
3523 /* That vertex got clipped
3524 * Contrary to OpenGL it is not dropped completely, it just
3525 * undergoes a different calculation.
3527 TRACE("Vertex got clipped\n");
3528 x += rhw;
3529 y += rhw;
3531 x /= 2;
3532 y /= 2;
3534 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3535 * outside of the main vertex buffer memory. That needs some more
3536 * investigation...
3540 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3543 ( (float *) dest_ptr)[0] = x;
3544 ( (float *) dest_ptr)[1] = y;
3545 ( (float *) dest_ptr)[2] = z;
3546 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3548 dest_ptr += 3 * sizeof(float);
3550 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3551 dest_ptr += sizeof(float);
3554 if(dest_conv) {
3555 float w = 1 / rhw;
3556 ( (float *) dest_conv)[0] = x * w;
3557 ( (float *) dest_conv)[1] = y * w;
3558 ( (float *) dest_conv)[2] = z * w;
3559 ( (float *) dest_conv)[3] = w;
3561 dest_conv += 3 * sizeof(float);
3563 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3564 dest_conv += sizeof(float);
3568 if (DestFVF & WINED3DFVF_PSIZE) {
3569 dest_ptr += sizeof(DWORD);
3570 if(dest_conv) dest_conv += sizeof(DWORD);
3572 if (DestFVF & WINED3DFVF_NORMAL) {
3573 float *normal =
3574 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3575 /* AFAIK this should go into the lighting information */
3576 FIXME("Didn't expect the destination to have a normal\n");
3577 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3578 if(dest_conv) {
3579 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3583 if (DestFVF & WINED3DFVF_DIFFUSE) {
3584 DWORD *color_d =
3585 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3586 if(!color_d) {
3587 static BOOL warned = FALSE;
3589 if(!warned) {
3590 ERR("No diffuse color in source, but destination has one\n");
3591 warned = TRUE;
3594 *( (DWORD *) dest_ptr) = 0xffffffff;
3595 dest_ptr += sizeof(DWORD);
3597 if(dest_conv) {
3598 *( (DWORD *) dest_conv) = 0xffffffff;
3599 dest_conv += sizeof(DWORD);
3602 else {
3603 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3604 if(dest_conv) {
3605 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3606 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3607 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3608 dest_conv += sizeof(DWORD);
3613 if (DestFVF & WINED3DFVF_SPECULAR) {
3614 /* What's the color value in the feedback buffer? */
3615 DWORD *color_s =
3616 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3617 if(!color_s) {
3618 static BOOL warned = FALSE;
3620 if(!warned) {
3621 ERR("No specular color in source, but destination has one\n");
3622 warned = TRUE;
3625 *( (DWORD *) dest_ptr) = 0xFF000000;
3626 dest_ptr += sizeof(DWORD);
3628 if(dest_conv) {
3629 *( (DWORD *) dest_conv) = 0xFF000000;
3630 dest_conv += sizeof(DWORD);
3633 else {
3634 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3635 if(dest_conv) {
3636 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3637 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3638 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3639 dest_conv += sizeof(DWORD);
3644 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3645 float *tex_coord =
3646 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3647 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3648 if(!tex_coord) {
3649 ERR("No source texture, but destination requests one\n");
3650 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3651 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3653 else {
3654 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3655 if(dest_conv) {
3656 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3662 if(dest_conv) {
3663 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3664 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3667 LEAVE_GL();
3669 return WINED3D_OK;
3671 #undef copy_and_next
3673 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3675 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3676 WineDirect3DVertexStridedData strided;
3677 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3679 if (!SrcImpl) {
3680 WARN("NULL source vertex buffer\n");
3681 return WINED3DERR_INVALIDCALL;
3683 /* We don't need the source vbo because this buffer is only used as
3684 * a source for ProcessVertices. Avoid wasting resources by converting the
3685 * buffer and loading the VBO
3687 if(SrcImpl->vbo) {
3688 TRACE("Releasing the source vbo, it won't be needed\n");
3690 if(!SrcImpl->resource.allocatedMemory) {
3691 /* Rescue the data from the buffer */
3692 void *src;
3693 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3694 if(!SrcImpl->resource.allocatedMemory) {
3695 ERR("Out of memory\n");
3696 return E_OUTOFMEMORY;
3699 ENTER_GL();
3700 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3701 checkGLcall("glBindBufferARB");
3703 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3704 if(src) {
3705 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3708 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3709 checkGLcall("glUnmapBufferARB");
3710 } else {
3711 ENTER_GL();
3714 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3715 checkGLcall("glBindBufferARB");
3716 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3717 checkGLcall("glDeleteBuffersARB");
3718 LEAVE_GL();
3720 SrcImpl->vbo = 0;
3723 memset(&strided, 0, sizeof(strided));
3724 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3726 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3729 /*****
3730 * Get / Set Texture Stage States
3731 * TODO: Verify against dx9 definitions
3732 *****/
3733 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3735 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3737 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3739 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3741 /* Reject invalid texture units */
3742 if (Stage >= GL_LIMITS(texture_stages)) {
3743 TRACE("Attempt to access invalid texture rejected\n");
3744 return WINED3DERR_INVALIDCALL;
3747 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3748 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3749 This->updateStateBlock->textureState[Stage][Type] = Value;
3751 if (This->isRecordingState) {
3752 TRACE("Recording... not performing anything\n");
3753 return WINED3D_OK;
3756 /* Checked after the assignments to allow proper stateblock recording */
3757 if(oldValue == Value) {
3758 TRACE("App is setting the old value over, nothing to do\n");
3759 return WINED3D_OK;
3762 if(Stage > This->stateBlock->lowest_disabled_stage &&
3763 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3764 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3765 * Changes in other states are important on disabled stages too
3767 return WINED3D_OK;
3770 if(Type == WINED3DTSS_COLOROP) {
3771 int i;
3773 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3774 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3775 * they have to be disabled
3777 * The current stage is dirtified below.
3779 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3780 TRACE("Additionally dirtifying stage %d\n", i);
3781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3783 This->stateBlock->lowest_disabled_stage = Stage;
3784 TRACE("New lowest disabled: %d\n", Stage);
3785 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3786 /* Previously disabled stage enabled. Stages above it may need enabling
3787 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3788 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3790 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3793 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3794 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3795 break;
3797 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3800 This->stateBlock->lowest_disabled_stage = i;
3801 TRACE("New lowest disabled: %d\n", i);
3803 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3804 /* TODO: Built a stage -> texture unit mapping for register combiners */
3808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3810 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3811 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3812 * will call FindTexUnitMap too.
3814 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3815 IWineD3DDeviceImpl_FindTexUnitMap(This);
3817 return WINED3D_OK;
3820 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3822 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3823 *pValue = This->updateStateBlock->textureState[Stage][Type];
3824 return WINED3D_OK;
3827 /*****
3828 * Get / Set Texture
3829 *****/
3830 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 IWineD3DBaseTexture *oldTexture;
3835 oldTexture = This->updateStateBlock->textures[Stage];
3836 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3838 #if 0 /* TODO: check so vertex textures */
3839 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3840 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3841 return WINED3D_OK;
3843 #endif
3845 /* Reject invalid texture units */
3846 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
3847 WARN("Attempt to access invalid texture rejected\n");
3848 return WINED3DERR_INVALIDCALL;
3851 if(pTexture != NULL) {
3852 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3854 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3855 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3856 return WINED3DERR_INVALIDCALL;
3858 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3861 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3862 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3864 This->updateStateBlock->set.textures[Stage] = TRUE;
3865 This->updateStateBlock->changed.textures[Stage] = TRUE;
3866 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3867 This->updateStateBlock->textures[Stage] = pTexture;
3869 /* Handle recording of state blocks */
3870 if (This->isRecordingState) {
3871 TRACE("Recording... not performing anything\n");
3872 return WINED3D_OK;
3875 if(oldTexture == pTexture) {
3876 TRACE("App is setting the same texture again, nothing to do\n");
3877 return WINED3D_OK;
3880 /** NOTE: MSDN says that setTexture increases the reference count,
3881 * and the the application nust set the texture back to null (or have a leaky application),
3882 * This means we should pass the refcount up to the parent
3883 *******************************/
3884 if (NULL != This->updateStateBlock->textures[Stage]) {
3885 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3886 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3888 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3889 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3890 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3891 * so the COLOROP and ALPHAOP have to be dirtified.
3893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3894 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3896 if(bindCount == 1) {
3897 new->baseTexture.sampler = Stage;
3899 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3903 if (NULL != oldTexture) {
3904 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3905 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3907 IWineD3DBaseTexture_Release(oldTexture);
3908 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3913 if(bindCount && old->baseTexture.sampler == Stage) {
3914 int i;
3915 /* Have to do a search for the other sampler(s) where the texture is bound to
3916 * Shouldn't happen as long as apps bind a texture only to one stage
3918 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3919 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3920 if(This->updateStateBlock->textures[i] == oldTexture) {
3921 old->baseTexture.sampler = i;
3922 break;
3928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3930 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3931 * pixel shader is used
3933 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3934 IWineD3DDeviceImpl_FindTexUnitMap(This);
3937 return WINED3D_OK;
3940 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3942 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3944 /* Reject invalid texture units */
3945 if (Stage >= GL_LIMITS(sampler_stages)) {
3946 TRACE("Attempt to access invalid texture rejected\n");
3947 return WINED3DERR_INVALIDCALL;
3949 *ppTexture=This->stateBlock->textures[Stage];
3950 if (*ppTexture)
3951 IWineD3DBaseTexture_AddRef(*ppTexture);
3953 return WINED3D_OK;
3956 /*****
3957 * Get Back Buffer
3958 *****/
3959 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3960 IWineD3DSurface **ppBackBuffer) {
3961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3962 IWineD3DSwapChain *swapChain;
3963 HRESULT hr;
3965 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3967 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3968 if (hr == WINED3D_OK) {
3969 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3970 IWineD3DSwapChain_Release(swapChain);
3971 } else {
3972 *ppBackBuffer = NULL;
3974 return hr;
3977 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3979 WARN("(%p) : stub, calling idirect3d for now\n", This);
3980 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3983 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3985 IWineD3DSwapChain *swapChain;
3986 HRESULT hr;
3988 if(iSwapChain > 0) {
3989 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3990 if (hr == WINED3D_OK) {
3991 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3992 IWineD3DSwapChain_Release(swapChain);
3993 } else {
3994 FIXME("(%p) Error getting display mode\n", This);
3996 } else {
3997 /* Don't read the real display mode,
3998 but return the stored mode instead. X11 can't change the color
3999 depth, and some apps are pretty angry if they SetDisplayMode from
4000 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4002 Also don't relay to the swapchain because with ddraw it's possible
4003 that there isn't a swapchain at all */
4004 pMode->Width = This->ddraw_width;
4005 pMode->Height = This->ddraw_height;
4006 pMode->Format = This->ddraw_format;
4007 pMode->RefreshRate = 0;
4008 hr = WINED3D_OK;
4011 return hr;
4014 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4016 TRACE("(%p)->(%p)\n", This, hWnd);
4018 if(This->ddraw_fullscreen) {
4019 if(This->ddraw_window && This->ddraw_window != hWnd) {
4020 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4022 if(hWnd && This->ddraw_window != hWnd) {
4023 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4027 This->ddraw_window = hWnd;
4028 return WINED3D_OK;
4031 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4033 TRACE("(%p)->(%p)\n", This, hWnd);
4035 *hWnd = This->ddraw_window;
4036 return WINED3D_OK;
4039 /*****
4040 * Stateblock related functions
4041 *****/
4043 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4045 IWineD3DStateBlockImpl *object;
4046 HRESULT temp_result;
4047 int i;
4049 TRACE("(%p)\n", This);
4051 if (This->isRecordingState) {
4052 return WINED3DERR_INVALIDCALL;
4055 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4056 if (NULL == object ) {
4057 FIXME("(%p)Error allocating memory for stateblock\n", This);
4058 return E_OUTOFMEMORY;
4060 TRACE("(%p) created object %p\n", This, object);
4061 object->wineD3DDevice= This;
4062 /** FIXME: object->parent = parent; **/
4063 object->parent = NULL;
4064 object->blockType = WINED3DSBT_ALL;
4065 object->ref = 1;
4066 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4068 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4069 list_init(&object->lightMap[i]);
4072 temp_result = allocate_shader_constants(object);
4073 if (WINED3D_OK != temp_result)
4074 return temp_result;
4076 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4077 This->updateStateBlock = object;
4078 This->isRecordingState = TRUE;
4080 TRACE("(%p) recording stateblock %p\n",This , object);
4081 return WINED3D_OK;
4084 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4087 if (!This->isRecordingState) {
4088 FIXME("(%p) not recording! returning error\n", This);
4089 *ppStateBlock = NULL;
4090 return WINED3DERR_INVALIDCALL;
4093 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4094 This->isRecordingState = FALSE;
4095 This->updateStateBlock = This->stateBlock;
4096 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4097 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4098 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4099 return WINED3D_OK;
4102 /*****
4103 * Scene related functions
4104 *****/
4105 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4106 /* At the moment we have no need for any functionality at the beginning
4107 of a scene */
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 TRACE("(%p)\n", This);
4111 if(This->inScene) {
4112 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4113 return WINED3DERR_INVALIDCALL;
4115 This->inScene = TRUE;
4116 return WINED3D_OK;
4119 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4121 TRACE("(%p)\n", This);
4123 if(!This->inScene) {
4124 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4125 return WINED3DERR_INVALIDCALL;
4128 ENTER_GL();
4129 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4130 glFlush();
4131 checkGLcall("glFlush");
4132 LEAVE_GL();
4134 This->inScene = FALSE;
4135 return WINED3D_OK;
4138 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4139 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4140 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4142 IWineD3DSwapChain *swapChain = NULL;
4143 int i;
4144 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4146 TRACE("(%p) Presenting the frame\n", This);
4148 for(i = 0 ; i < swapchains ; i ++) {
4150 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4151 TRACE("presentinng chain %d, %p\n", i, swapChain);
4152 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4153 IWineD3DSwapChain_Release(swapChain);
4156 return WINED3D_OK;
4159 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4160 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4163 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4164 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4165 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4166 GLbitfield glMask = 0;
4167 GLboolean old_ztest;
4168 GLfloat old_z_clear_value;
4169 GLint old_stencil_clear_value;
4170 GLfloat old_color_clear_value[4];
4171 unsigned int i;
4172 CONST WINED3DRECT* curRect;
4174 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4175 Count, pRects, Flags, Z, Stencil);
4177 ENTER_GL();
4179 glEnable(GL_SCISSOR_TEST);
4180 checkGLcall("glEnable GL_SCISSOR_TEST");
4182 if (Count > 0 && pRects) {
4183 curRect = pRects;
4184 } else {
4185 curRect = NULL;
4188 /* Only set the values up once, as they are not changing */
4189 if (Flags & WINED3DCLEAR_STENCIL) {
4190 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4191 glClearStencil(Stencil);
4192 checkGLcall("glClearStencil");
4193 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4194 glStencilMask(0xFFFFFFFF);
4197 if (Flags & WINED3DCLEAR_ZBUFFER) {
4198 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4199 glDepthMask(GL_TRUE);
4200 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4201 glClearDepth(Z);
4202 checkGLcall("glClearDepth");
4203 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4206 if (Flags & WINED3DCLEAR_TARGET) {
4207 TRACE("Clearing screen with glClear to color %x\n", Color);
4208 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4209 glClearColor(D3DCOLOR_R(Color),
4210 D3DCOLOR_G(Color),
4211 D3DCOLOR_B(Color),
4212 D3DCOLOR_A(Color));
4213 checkGLcall("glClearColor");
4215 /* Clear ALL colors! */
4216 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4217 glMask = glMask | GL_COLOR_BUFFER_BIT;
4220 /* Now process each rect in turn */
4221 for (i = 0; i < Count || i == 0; i++) {
4223 if (curRect) {
4224 /* Note gl uses lower left, width/height */
4225 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4226 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4227 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4228 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4229 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4230 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4231 checkGLcall("glScissor");
4232 } else {
4233 glScissor(This->stateBlock->viewport.X,
4234 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4235 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4236 This->stateBlock->viewport.Width,
4237 This->stateBlock->viewport.Height);
4238 checkGLcall("glScissor");
4241 /* Clear the selected rectangle (or full screen) */
4242 glClear(glMask);
4243 checkGLcall("glClear");
4245 /* Step to the next rectangle */
4246 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4249 /* Restore the old values (why..?) */
4250 if (Flags & WINED3DCLEAR_STENCIL) {
4251 glClearStencil(old_stencil_clear_value);
4252 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4254 if (Flags & WINED3DCLEAR_ZBUFFER) {
4255 glDepthMask(old_ztest);
4256 glClearDepth(old_z_clear_value);
4258 if (Flags & WINED3DCLEAR_TARGET) {
4259 glClearColor(old_color_clear_value[0],
4260 old_color_clear_value[1],
4261 old_color_clear_value[2],
4262 old_color_clear_value[3]);
4263 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4264 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4265 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4266 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4269 glDisable(GL_SCISSOR_TEST);
4270 checkGLcall("glDisable");
4271 LEAVE_GL();
4273 return WINED3D_OK;
4276 /*****
4277 * Drawing functions
4278 *****/
4279 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4280 UINT PrimitiveCount) {
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 This->stateBlock->streamIsUP = FALSE;
4285 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4286 debug_d3dprimitivetype(PrimitiveType),
4287 StartVertex, PrimitiveCount);
4289 if(This->stateBlock->loadBaseVertexIndex != 0) {
4290 This->stateBlock->loadBaseVertexIndex = 0;
4291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4293 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4294 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4295 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4296 return WINED3D_OK;
4299 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4300 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4301 WINED3DPRIMITIVETYPE PrimitiveType,
4302 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 UINT idxStride = 2;
4306 IWineD3DIndexBuffer *pIB;
4307 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4309 pIB = This->stateBlock->pIndexData;
4310 This->stateBlock->streamIsUP = FALSE;
4312 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4313 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4314 minIndex, NumVertices, startIndex, primCount);
4316 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4317 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4318 idxStride = 2;
4319 } else {
4320 idxStride = 4;
4323 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4324 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4328 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4329 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4331 return WINED3D_OK;
4334 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4335 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4336 UINT VertexStreamZeroStride) {
4337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4339 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4340 debug_d3dprimitivetype(PrimitiveType),
4341 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4343 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4344 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4345 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4346 This->stateBlock->streamIsUP = TRUE;
4347 This->stateBlock->loadBaseVertexIndex = 0;
4349 /* TODO: Only mark dirty if drawing from a different UP address */
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4352 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4353 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4355 /* MSDN specifies stream zero settings must be set to NULL */
4356 This->stateBlock->streamStride[0] = 0;
4357 This->stateBlock->streamSource[0] = NULL;
4359 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4360 * the new stream sources or use UP drawing again
4362 return WINED3D_OK;
4365 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4366 UINT MinVertexIndex, UINT NumVertices,
4367 UINT PrimitiveCount, CONST void* pIndexData,
4368 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4369 UINT VertexStreamZeroStride) {
4370 int idxStride;
4371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4373 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4374 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4375 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4376 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4378 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4379 idxStride = 2;
4380 } else {
4381 idxStride = 4;
4384 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4385 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4386 This->stateBlock->streamIsUP = TRUE;
4387 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4389 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4390 This->stateBlock->baseVertexIndex = 0;
4391 This->stateBlock->loadBaseVertexIndex = 0;
4392 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4395 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4397 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4398 This->stateBlock->streamSource[0] = NULL;
4399 This->stateBlock->streamStride[0] = 0;
4400 This->stateBlock->pIndexData = NULL;
4401 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4402 * SetStreamSource to specify a vertex buffer
4405 return WINED3D_OK;
4408 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4411 /* Mark the state dirty until we have nicer tracking
4412 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4413 * that value.
4415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4416 This->stateBlock->baseVertexIndex = 0;
4417 This->up_strided = DrawPrimStrideData;
4418 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4419 This->up_strided = NULL;
4420 return WINED3D_OK;
4422 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4423 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4425 HRESULT hr = WINED3D_OK;
4426 WINED3DRESOURCETYPE sourceType;
4427 WINED3DRESOURCETYPE destinationType;
4428 int i ,levels;
4430 /* TODO: think about moving the code into IWineD3DBaseTexture */
4432 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4434 /* verify that the source and destination textures aren't NULL */
4435 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4436 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4437 This, pSourceTexture, pDestinationTexture);
4438 hr = WINED3DERR_INVALIDCALL;
4441 if (pSourceTexture == pDestinationTexture) {
4442 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4443 This, pSourceTexture, pDestinationTexture);
4444 hr = WINED3DERR_INVALIDCALL;
4446 /* Verify that the source and destination textures are the same type */
4447 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4448 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4450 if (sourceType != destinationType) {
4451 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4452 This);
4453 hr = WINED3DERR_INVALIDCALL;
4456 /* check that both textures have the identical numbers of levels */
4457 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4458 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4459 hr = WINED3DERR_INVALIDCALL;
4462 if (WINED3D_OK == hr) {
4464 /* Make sure that the destination texture is loaded */
4465 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4467 /* Update every surface level of the texture */
4468 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4470 switch (sourceType) {
4471 case WINED3DRTYPE_TEXTURE:
4473 IWineD3DSurface *srcSurface;
4474 IWineD3DSurface *destSurface;
4476 for (i = 0 ; i < levels ; ++i) {
4477 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4478 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4479 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4480 IWineD3DSurface_Release(srcSurface);
4481 IWineD3DSurface_Release(destSurface);
4482 if (WINED3D_OK != hr) {
4483 WARN("(%p) : Call to update surface failed\n", This);
4484 return hr;
4488 break;
4489 case WINED3DRTYPE_CUBETEXTURE:
4491 IWineD3DSurface *srcSurface;
4492 IWineD3DSurface *destSurface;
4493 WINED3DCUBEMAP_FACES faceType;
4495 for (i = 0 ; i < levels ; ++i) {
4496 /* Update each cube face */
4497 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4498 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4499 if (WINED3D_OK != hr) {
4500 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4501 } else {
4502 TRACE("Got srcSurface %p\n", srcSurface);
4504 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4505 if (WINED3D_OK != hr) {
4506 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4507 } else {
4508 TRACE("Got desrSurface %p\n", destSurface);
4510 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4511 IWineD3DSurface_Release(srcSurface);
4512 IWineD3DSurface_Release(destSurface);
4513 if (WINED3D_OK != hr) {
4514 WARN("(%p) : Call to update surface failed\n", This);
4515 return hr;
4520 break;
4521 #if 0 /* TODO: Add support for volume textures */
4522 case WINED3DRTYPE_VOLUMETEXTURE:
4524 IWineD3DVolume srcVolume = NULL;
4525 IWineD3DSurface destVolume = NULL;
4527 for (i = 0 ; i < levels ; ++i) {
4528 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4529 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4530 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4531 IWineD3DVolume_Release(srcSurface);
4532 IWineD3DVolume_Release(destSurface);
4533 if (WINED3D_OK != hr) {
4534 WARN("(%p) : Call to update volume failed\n", This);
4535 return hr;
4539 break;
4540 #endif
4541 default:
4542 FIXME("(%p) : Unsupported source and destination type\n", This);
4543 hr = WINED3DERR_INVALIDCALL;
4547 return hr;
4550 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4551 IWineD3DSwapChain *swapChain;
4552 HRESULT hr;
4553 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4554 if(hr == WINED3D_OK) {
4555 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4556 IWineD3DSwapChain_Release(swapChain);
4558 return hr;
4561 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4563 /* return a sensible default */
4564 *pNumPasses = 1;
4565 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4566 FIXME("(%p) : stub\n", This);
4567 return WINED3D_OK;
4570 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 int j;
4573 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4574 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4575 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4576 return WINED3DERR_INVALIDCALL;
4578 for (j = 0; j < 256; ++j) {
4579 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4580 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4581 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4582 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4584 TRACE("(%p) : returning\n", This);
4585 return WINED3D_OK;
4588 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4590 int j;
4591 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4592 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4593 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4594 return WINED3DERR_INVALIDCALL;
4596 for (j = 0; j < 256; ++j) {
4597 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4598 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4599 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4600 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4602 TRACE("(%p) : returning\n", This);
4603 return WINED3D_OK;
4606 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4609 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4610 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4611 return WINED3DERR_INVALIDCALL;
4613 /*TODO: stateblocks */
4614 This->currentPalette = PaletteNumber;
4615 TRACE("(%p) : returning\n", This);
4616 return WINED3D_OK;
4619 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4621 if (PaletteNumber == NULL) {
4622 WARN("(%p) : returning Invalid Call\n", This);
4623 return WINED3DERR_INVALIDCALL;
4625 /*TODO: stateblocks */
4626 *PaletteNumber = This->currentPalette;
4627 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4628 return WINED3D_OK;
4631 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 static BOOL showFixmes = TRUE;
4634 if (showFixmes) {
4635 FIXME("(%p) : stub\n", This);
4636 showFixmes = FALSE;
4639 This->softwareVertexProcessing = bSoftware;
4640 return WINED3D_OK;
4644 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4646 static BOOL showFixmes = TRUE;
4647 if (showFixmes) {
4648 FIXME("(%p) : stub\n", This);
4649 showFixmes = FALSE;
4651 return This->softwareVertexProcessing;
4655 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 IWineD3DSwapChain *swapChain;
4658 HRESULT hr;
4660 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4662 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4663 if(hr == WINED3D_OK){
4664 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4665 IWineD3DSwapChain_Release(swapChain);
4666 }else{
4667 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4669 return hr;
4673 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 static BOOL showfixmes = TRUE;
4676 if(nSegments != 0.0f) {
4677 if( showfixmes) {
4678 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4679 showfixmes = FALSE;
4682 return WINED3D_OK;
4685 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4687 static BOOL showfixmes = TRUE;
4688 if( showfixmes) {
4689 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4690 showfixmes = FALSE;
4692 return 0.0f;
4695 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4697 /** TODO: remove casts to IWineD3DSurfaceImpl
4698 * NOTE: move code to surface to accomplish this
4699 ****************************************/
4700 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4701 int srcWidth, srcHeight;
4702 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4703 WINED3DFORMAT destFormat, srcFormat;
4704 UINT destSize;
4705 int srcLeft, destLeft, destTop;
4706 WINED3DPOOL srcPool, destPool;
4707 int offset = 0;
4708 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4709 glDescriptor *glDescription = NULL;
4710 GLenum textureDimensions = GL_TEXTURE_2D;
4711 IWineD3DBaseTexture *baseTexture;
4713 WINED3DSURFACE_DESC winedesc;
4715 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4716 memset(&winedesc, 0, sizeof(winedesc));
4717 winedesc.Width = &srcSurfaceWidth;
4718 winedesc.Height = &srcSurfaceHeight;
4719 winedesc.Pool = &srcPool;
4720 winedesc.Format = &srcFormat;
4722 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4724 winedesc.Width = &destSurfaceWidth;
4725 winedesc.Height = &destSurfaceHeight;
4726 winedesc.Pool = &destPool;
4727 winedesc.Format = &destFormat;
4728 winedesc.Size = &destSize;
4730 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4732 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4733 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4734 return WINED3DERR_INVALIDCALL;
4737 if (destFormat == WINED3DFMT_UNKNOWN) {
4738 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4739 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4741 /* Get the update surface description */
4742 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4745 /* Make sure the surface is loaded and up to date */
4746 IWineD3DSurface_PreLoad(pDestinationSurface);
4748 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4750 ENTER_GL();
4752 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4753 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4754 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4755 srcLeft = pSourceRect ? pSourceRect->left : 0;
4756 destLeft = pDestPoint ? pDestPoint->x : 0;
4757 destTop = pDestPoint ? pDestPoint->y : 0;
4760 /* This function doesn't support compressed textures
4761 the pitch is just bytesPerPixel * width */
4762 if(srcWidth != srcSurfaceWidth || srcLeft ){
4763 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4764 offset += srcLeft * pSrcSurface->bytesPerPixel;
4765 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4767 /* TODO DXT formats */
4769 if(pSourceRect != NULL && pSourceRect->top != 0){
4770 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4772 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4773 ,This
4774 ,glDescription->level
4775 ,destLeft
4776 ,destTop
4777 ,srcWidth
4778 ,srcHeight
4779 ,glDescription->glFormat
4780 ,glDescription->glType
4781 ,IWineD3DSurface_GetData(pSourceSurface)
4784 /* Sanity check */
4785 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4787 /* need to lock the surface to get the data */
4788 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4791 /* TODO: Cube and volume support */
4792 if(rowoffset != 0){
4793 /* not a whole row so we have to do it a line at a time */
4794 int j;
4796 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4797 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4799 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4801 glTexSubImage2D(glDescription->target
4802 ,glDescription->level
4803 ,destLeft
4805 ,srcWidth
4807 ,glDescription->glFormat
4808 ,glDescription->glType
4809 ,data /* could be quicker using */
4811 data += rowoffset;
4814 } else { /* Full width, so just write out the whole texture */
4816 if (WINED3DFMT_DXT1 == destFormat ||
4817 WINED3DFMT_DXT2 == destFormat ||
4818 WINED3DFMT_DXT3 == destFormat ||
4819 WINED3DFMT_DXT4 == destFormat ||
4820 WINED3DFMT_DXT5 == destFormat) {
4821 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4822 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4823 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4824 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4825 } if (destFormat != srcFormat) {
4826 FIXME("Updating mixed format compressed texture is not curretly support\n");
4827 } else {
4828 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4829 glDescription->level,
4830 glDescription->glFormatInternal,
4831 srcWidth,
4832 srcHeight,
4834 destSize,
4835 IWineD3DSurface_GetData(pSourceSurface));
4837 } else {
4838 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4842 } else {
4843 glTexSubImage2D(glDescription->target
4844 ,glDescription->level
4845 ,destLeft
4846 ,destTop
4847 ,srcWidth
4848 ,srcHeight
4849 ,glDescription->glFormat
4850 ,glDescription->glType
4851 ,IWineD3DSurface_GetData(pSourceSurface)
4855 checkGLcall("glTexSubImage2D");
4856 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4858 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4859 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4860 * surface bigger than it needs to be hmm.. */
4861 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4862 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4863 IWineD3DBaseTexture_Release(baseTexture);
4866 glDisable(textureDimensions); /* This needs to be managed better.... */
4867 LEAVE_GL();
4869 return WINED3D_OK;
4872 /* Implementation details at http://developer.nvidia.com/attach/6494
4874 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4875 hmm.. no longer supported use
4876 OpenGL evaluators or tessellate surfaces within your application.
4879 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4880 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4883 FIXME("(%p) : Stub\n", This);
4884 return WINED3D_OK;
4888 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4889 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4892 FIXME("(%p) : Stub\n", This);
4893 return WINED3D_OK;
4896 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4898 TRACE("(%p) Handle(%d)\n", This, Handle);
4899 FIXME("(%p) : Stub\n", This);
4900 return WINED3D_OK;
4903 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4905 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4906 DDBLTFX BltFx;
4907 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4909 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4910 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4911 return WINED3DERR_INVALIDCALL;
4914 /* Just forward this to the DirectDraw blitting engine */
4915 memset(&BltFx, 0, sizeof(BltFx));
4916 BltFx.dwSize = sizeof(BltFx);
4917 BltFx.u5.dwFillColor = color;
4918 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4921 /* rendertarget and deptth stencil functions */
4922 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4926 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4927 return WINED3DERR_INVALIDCALL;
4930 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4931 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4932 /* Note inc ref on returned surface */
4933 if(*ppRenderTarget != NULL)
4934 IWineD3DSurface_AddRef(*ppRenderTarget);
4935 return WINED3D_OK;
4938 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4940 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4941 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4942 IWineD3DSwapChainImpl *Swapchain;
4943 HRESULT hr;
4945 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4947 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4948 if(hr != WINED3D_OK) {
4949 ERR("Can't get the swapchain\n");
4950 return hr;
4953 /* Make sure to release the swapchain */
4954 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4956 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4957 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4958 return WINED3DERR_INVALIDCALL;
4960 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4961 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4962 return WINED3DERR_INVALIDCALL;
4965 if(Swapchain->frontBuffer != Front) {
4966 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4968 if(Swapchain->frontBuffer)
4969 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4970 Swapchain->frontBuffer = Front;
4972 if(Swapchain->frontBuffer) {
4973 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4977 if(Back && !Swapchain->backBuffer) {
4978 /* We need memory for the back buffer array - only one back buffer this way */
4979 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4980 if(!Swapchain->backBuffer) {
4981 ERR("Out of memory\n");
4982 return E_OUTOFMEMORY;
4986 if(Swapchain->backBuffer[0] != Back) {
4987 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4988 ENTER_GL();
4989 if(!Swapchain->backBuffer[0]) {
4990 /* GL was told to draw to the front buffer at creation,
4991 * undo that
4993 glDrawBuffer(GL_BACK);
4994 checkGLcall("glDrawBuffer(GL_BACK)");
4995 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4996 Swapchain->presentParms.BackBufferCount = 1;
4997 } else if (!Back) {
4998 /* That makes problems - disable for now */
4999 /* glDrawBuffer(GL_FRONT); */
5000 checkGLcall("glDrawBuffer(GL_FRONT)");
5001 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5002 Swapchain->presentParms.BackBufferCount = 0;
5004 LEAVE_GL();
5006 if(Swapchain->backBuffer[0])
5007 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5008 Swapchain->backBuffer[0] = Back;
5010 if(Swapchain->backBuffer[0]) {
5011 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5012 } else {
5013 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5018 return WINED3D_OK;
5021 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5023 *ppZStencilSurface = This->depthStencilBuffer;
5024 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5026 if(*ppZStencilSurface != NULL) {
5027 /* Note inc ref on returned surface */
5028 IWineD3DSurface_AddRef(*ppZStencilSurface);
5030 return WINED3D_OK;
5033 static void bind_fbo(IWineD3DDevice *iface) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5036 if (!This->fbo) {
5037 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5038 checkGLcall("glGenFramebuffersEXT()");
5040 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5041 checkGLcall("glBindFramebuffer()");
5044 /* TODO: Handle stencil attachments */
5045 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5047 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5049 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5051 bind_fbo(iface);
5053 if (depth_stencil_impl) {
5054 GLenum texttarget, target;
5055 GLint old_binding = 0;
5057 IWineD3DSurface_PreLoad(depth_stencil);
5058 texttarget = depth_stencil_impl->glDescription.target;
5059 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5061 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5062 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5063 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5064 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5065 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5066 glBindTexture(target, old_binding);
5068 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5069 checkGLcall("glFramebufferTexture2DEXT()");
5070 } else {
5071 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5072 checkGLcall("glFramebufferTexture2DEXT()");
5075 if (!This->render_offscreen) {
5076 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5077 checkGLcall("glBindFramebuffer()");
5081 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5085 if (idx >= GL_LIMITS(buffers)) {
5086 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5089 bind_fbo(iface);
5091 if (rtimpl) {
5092 GLenum texttarget, target;
5093 GLint old_binding = 0;
5095 IWineD3DSurface_PreLoad(render_target);
5096 texttarget = rtimpl->glDescription.target;
5097 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5099 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5100 glBindTexture(target, rtimpl->glDescription.textureName);
5101 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5102 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5103 glBindTexture(target, old_binding);
5105 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5106 checkGLcall("glFramebufferTexture2DEXT()");
5108 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5109 } else {
5110 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5111 checkGLcall("glFramebufferTexture2DEXT()");
5113 This->draw_buffers[idx] = GL_NONE;
5116 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5117 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5118 checkGLcall("glDrawBuffers()");
5121 if (!This->render_offscreen) {
5122 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5123 checkGLcall("glBindFramebuffer()");
5127 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 WINED3DVIEWPORT viewport;
5131 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5133 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5134 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5135 return WINED3DERR_INVALIDCALL;
5138 /* MSDN says that null disables the render target
5139 but a device must always be associated with a render target
5140 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5142 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5143 for more details
5145 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5146 FIXME("Trying to set render target 0 to NULL\n");
5147 return WINED3DERR_INVALIDCALL;
5149 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5150 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);
5151 return WINED3DERR_INVALIDCALL;
5154 /* If we are trying to set what we already have, don't bother */
5155 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5156 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5157 return WINED3D_OK;
5159 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5160 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5161 This->render_targets[RenderTargetIndex] = pRenderTarget;
5163 /* Render target 0 is special */
5164 if(RenderTargetIndex == 0) {
5165 /* Finally, reset the viewport as the MSDN states. */
5166 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5167 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5168 viewport.X = 0;
5169 viewport.Y = 0;
5170 viewport.MaxZ = 1.0f;
5171 viewport.MinZ = 0.0f;
5172 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5174 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5175 * ctx properly.
5176 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5177 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5179 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5180 } else {
5181 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5182 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5184 return WINED3D_OK;
5187 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5189 HRESULT hr = WINED3D_OK;
5190 IWineD3DSurface *tmp;
5192 TRACE("(%p) Swapping z-buffer\n",This);
5194 if (pNewZStencil == This->stencilBufferTarget) {
5195 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5196 } else {
5197 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5198 * depending on the renter target implementation being used.
5199 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5200 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5201 * stencil buffer and incure an extra memory overhead
5202 ******************************************************/
5205 tmp = This->stencilBufferTarget;
5206 This->stencilBufferTarget = pNewZStencil;
5207 /* should we be calling the parent or the wined3d surface? */
5208 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5209 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5210 hr = WINED3D_OK;
5211 /** TODO: glEnable/glDisable on depth/stencil depending on
5212 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5213 **********************************************************/
5214 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5215 set_depth_stencil_fbo(iface, pNewZStencil);
5219 return hr;
5222 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5223 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5225 /* TODO: the use of Impl is deprecated. */
5226 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5228 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5230 /* some basic validation checks */
5231 if(This->cursorTexture) {
5232 ENTER_GL();
5233 glDeleteTextures(1, &This->cursorTexture);
5234 LEAVE_GL();
5235 This->cursorTexture = 0;
5238 if(pCursorBitmap) {
5239 /* MSDN: Cursor must be A8R8G8B8 */
5240 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5241 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5242 return WINED3DERR_INVALIDCALL;
5245 /* MSDN: Cursor must be smaller than the display mode */
5246 if(pSur->currentDesc.Width > This->ddraw_width ||
5247 pSur->currentDesc.Height > This->ddraw_height) {
5248 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);
5249 return WINED3DERR_INVALIDCALL;
5252 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5253 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5254 * Texture and Blitting code to draw the cursor
5256 pSur->Flags |= SFLAG_FORCELOAD;
5257 IWineD3DSurface_PreLoad(pCursorBitmap);
5258 pSur->Flags &= ~SFLAG_FORCELOAD;
5259 /* Do not store the surface's pointer because the application may release
5260 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5261 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5263 This->cursorTexture = pSur->glDescription.textureName;
5264 This->cursorWidth = pSur->currentDesc.Width;
5265 This->cursorHeight = pSur->currentDesc.Height;
5266 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5269 This->xHotSpot = XHotSpot;
5270 This->yHotSpot = YHotSpot;
5271 return WINED3D_OK;
5274 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5276 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5278 This->xScreenSpace = XScreenSpace;
5279 This->yScreenSpace = YScreenSpace;
5281 return;
5285 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5287 BOOL oldVisible = This->bCursorVisible;
5288 TRACE("(%p) : visible(%d)\n", This, bShow);
5290 if(This->cursorTexture)
5291 This->bCursorVisible = bShow;
5293 return oldVisible;
5296 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5298 TRACE("(%p) : state (%u)\n", This, This->state);
5299 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5300 switch (This->state) {
5301 case WINED3D_OK:
5302 return WINED3D_OK;
5303 case WINED3DERR_DEVICELOST:
5305 ResourceList *resourceList = This->resources;
5306 while (NULL != resourceList) {
5307 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5308 return WINED3DERR_DEVICENOTRESET;
5309 resourceList = resourceList->next;
5311 return WINED3DERR_DEVICELOST;
5313 case WINED3DERR_DRIVERINTERNALERROR:
5314 return WINED3DERR_DRIVERINTERNALERROR;
5317 /* Unknown state */
5318 return WINED3DERR_DRIVERINTERNALERROR;
5322 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5324 /** FIXME: Resource tracking needs to be done,
5325 * The closes we can do to this is set the priorities of all managed textures low
5326 * and then reset them.
5327 ***********************************************************/
5328 FIXME("(%p) : stub\n", This);
5329 return WINED3D_OK;
5332 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5333 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5335 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5336 if(surface->Flags & SFLAG_DIBSECTION) {
5337 /* Release the DC */
5338 SelectObject(surface->hDC, surface->dib.holdbitmap);
5339 DeleteDC(surface->hDC);
5340 /* Release the DIB section */
5341 DeleteObject(surface->dib.DIBsection);
5342 surface->dib.bitmap_data = NULL;
5343 surface->resource.allocatedMemory = NULL;
5344 surface->Flags &= ~SFLAG_DIBSECTION;
5346 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
5347 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
5348 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5349 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
5350 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
5351 } else {
5352 surface->pow2Width = surface->pow2Height = 1;
5353 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5354 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5356 if(surface->glDescription.textureName) {
5357 ENTER_GL();
5358 glDeleteTextures(1, &surface->glDescription.textureName);
5359 LEAVE_GL();
5360 surface->glDescription.textureName = 0;
5362 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
5363 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
5364 surface->Flags |= SFLAG_NONPOW2;
5365 } else {
5366 surface->Flags &= ~SFLAG_NONPOW2;
5368 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5369 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5372 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5374 IWineD3DSwapChainImpl *swapchain;
5375 HRESULT hr;
5376 BOOL DisplayModeChanged = FALSE;
5377 WINED3DDISPLAYMODE mode;
5378 TRACE("(%p)\n", This);
5380 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5381 if(FAILED(hr)) {
5382 ERR("Failed to get the first implicit swapchain\n");
5383 return hr;
5386 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5387 * on an existing gl context, so there's no real need for recreation.
5389 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5391 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5393 TRACE("New params:\n");
5394 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
5395 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
5396 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
5397 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
5398 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
5399 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
5400 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
5401 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
5402 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
5403 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5404 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
5405 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
5406 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
5408 /* No special treatment of these parameters. Just store them */
5409 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
5410 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
5411 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
5412 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
5414 /* What to do about these? */
5415 if(*pPresentationParameters->BackBufferCount != 0 &&
5416 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5417 ERR("Cannot change the back buffer count yet\n");
5419 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5420 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5421 ERR("Cannot change the back buffer format yet\n");
5423 if(*pPresentationParameters->hDeviceWindow != NULL &&
5424 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5425 ERR("Cannot change the device window yet\n");
5427 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5428 ERR("What do do about a changed auto depth stencil parameter?\n");
5431 if(*pPresentationParameters->Windowed) {
5432 mode.Width = swapchain->orig_width;
5433 mode.Height = swapchain->orig_height;
5434 mode.RefreshRate = 0;
5435 mode.Format = swapchain->presentParms.BackBufferFormat;
5436 } else {
5437 mode.Width = *pPresentationParameters->BackBufferWidth;
5438 mode.Height = *pPresentationParameters->BackBufferHeight;
5439 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
5440 mode.Format = swapchain->presentParms.BackBufferFormat;
5443 /* Should Width == 800 && Height == 0 set 800x600? */
5444 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
5445 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5446 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5448 WINED3DVIEWPORT vp;
5449 int i;
5451 vp.X = 0;
5452 vp.Y = 0;
5453 vp.Width = *pPresentationParameters->BackBufferWidth;
5454 vp.Height = *pPresentationParameters->BackBufferHeight;
5455 vp.MinZ = 0;
5456 vp.MaxZ = 1;
5458 if(!*pPresentationParameters->Windowed) {
5459 DisplayModeChanged = TRUE;
5461 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
5462 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
5464 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5465 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5466 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5469 /* Now set the new viewport */
5470 IWineD3DDevice_SetViewport(iface, &vp);
5473 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5474 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
5475 DisplayModeChanged) {
5477 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5478 if(!(*pPresentationParameters->Windowed)) {
5479 IWineD3DDevice_SetFullscreen(iface, TRUE);
5482 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5484 /* Switching out of fullscreen mode? First set the original res, then change the window */
5485 if(*pPresentationParameters->Windowed) {
5486 IWineD3DDevice_SetFullscreen(iface, FALSE);
5488 swapchain->presentParms.Windowed = *pPresentationParameters->Windowed;
5491 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5492 return WINED3D_OK;
5495 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5497 /** FIXME: always true at the moment **/
5498 if(!bEnableDialogs) {
5499 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5501 return WINED3D_OK;
5505 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5507 TRACE("(%p) : pParameters %p\n", This, pParameters);
5509 *pParameters = This->createParms;
5510 return WINED3D_OK;
5513 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5514 IWineD3DSwapChain *swapchain;
5515 HRESULT hrc = WINED3D_OK;
5517 TRACE("Relaying to swapchain\n");
5519 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5520 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5521 IWineD3DSwapChain_Release(swapchain);
5523 return;
5526 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5527 IWineD3DSwapChain *swapchain;
5528 HRESULT hrc = WINED3D_OK;
5530 TRACE("Relaying to swapchain\n");
5532 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5533 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5534 IWineD3DSwapChain_Release(swapchain);
5536 return;
5540 /** ********************************************************
5541 * Notification functions
5542 ** ********************************************************/
5543 /** This function must be called in the release of a resource when ref == 0,
5544 * the contents of resource must still be correct,
5545 * any handels to other resource held by the caller must be closed
5546 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5547 *****************************************************/
5548 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5550 ResourceList* resourceList;
5552 TRACE("(%p) : resource %p\n", This, resource);
5553 #if 0
5554 EnterCriticalSection(&resourceStoreCriticalSection);
5555 #endif
5556 /* add a new texture to the frot of the linked list */
5557 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5558 resourceList->resource = resource;
5560 /* Get the old head */
5561 resourceList->next = This->resources;
5563 This->resources = resourceList;
5564 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5566 #if 0
5567 LeaveCriticalSection(&resourceStoreCriticalSection);
5568 #endif
5569 return;
5572 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5574 ResourceList* resourceList = NULL;
5575 ResourceList* previousResourceList = NULL;
5577 TRACE("(%p) : resource %p\n", This, resource);
5579 #if 0
5580 EnterCriticalSection(&resourceStoreCriticalSection);
5581 #endif
5582 resourceList = This->resources;
5584 while (resourceList != NULL) {
5585 if(resourceList->resource == resource) break;
5586 previousResourceList = resourceList;
5587 resourceList = resourceList->next;
5590 if (resourceList == NULL) {
5591 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5592 #if 0
5593 LeaveCriticalSection(&resourceStoreCriticalSection);
5594 #endif
5595 return;
5596 } else {
5597 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5599 /* make sure we don't leave a hole in the list */
5600 if (previousResourceList != NULL) {
5601 previousResourceList->next = resourceList->next;
5602 } else {
5603 This->resources = resourceList->next;
5606 #if 0
5607 LeaveCriticalSection(&resourceStoreCriticalSection);
5608 #endif
5609 return;
5613 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5615 int counter;
5617 TRACE("(%p) : resource %p\n", This, resource);
5618 switch(IWineD3DResource_GetType(resource)){
5619 case WINED3DRTYPE_SURFACE:
5620 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5621 break;
5622 case WINED3DRTYPE_TEXTURE:
5623 case WINED3DRTYPE_CUBETEXTURE:
5624 case WINED3DRTYPE_VOLUMETEXTURE:
5625 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5626 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5627 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5628 This->stateBlock->textures[counter] = NULL;
5630 if (This->updateStateBlock != This->stateBlock ){
5631 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5632 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5633 This->updateStateBlock->textures[counter] = NULL;
5637 break;
5638 case WINED3DRTYPE_VOLUME:
5639 /* TODO: nothing really? */
5640 break;
5641 case WINED3DRTYPE_VERTEXBUFFER:
5642 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5644 int streamNumber;
5645 TRACE("Cleaning up stream pointers\n");
5647 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5648 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5649 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5651 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5652 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5653 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5654 This->updateStateBlock->streamSource[streamNumber] = 0;
5655 /* Set changed flag? */
5658 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) */
5659 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5660 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5661 This->stateBlock->streamSource[streamNumber] = 0;
5664 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5665 else { /* This shouldn't happen */
5666 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5668 #endif
5672 break;
5673 case WINED3DRTYPE_INDEXBUFFER:
5674 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5675 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5676 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5677 This->updateStateBlock->pIndexData = NULL;
5680 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5681 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5682 This->stateBlock->pIndexData = NULL;
5686 break;
5687 default:
5688 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5689 break;
5693 /* Remove the resoruce from the resourceStore */
5694 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5696 TRACE("Resource released\n");
5700 /**********************************************************
5701 * IWineD3DDevice VTbl follows
5702 **********************************************************/
5704 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5706 /*** IUnknown methods ***/
5707 IWineD3DDeviceImpl_QueryInterface,
5708 IWineD3DDeviceImpl_AddRef,
5709 IWineD3DDeviceImpl_Release,
5710 /*** IWineD3DDevice methods ***/
5711 IWineD3DDeviceImpl_GetParent,
5712 /*** Creation methods**/
5713 IWineD3DDeviceImpl_CreateVertexBuffer,
5714 IWineD3DDeviceImpl_CreateIndexBuffer,
5715 IWineD3DDeviceImpl_CreateStateBlock,
5716 IWineD3DDeviceImpl_CreateSurface,
5717 IWineD3DDeviceImpl_CreateTexture,
5718 IWineD3DDeviceImpl_CreateVolumeTexture,
5719 IWineD3DDeviceImpl_CreateVolume,
5720 IWineD3DDeviceImpl_CreateCubeTexture,
5721 IWineD3DDeviceImpl_CreateQuery,
5722 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5723 IWineD3DDeviceImpl_CreateVertexDeclaration,
5724 IWineD3DDeviceImpl_CreateVertexShader,
5725 IWineD3DDeviceImpl_CreatePixelShader,
5726 IWineD3DDeviceImpl_CreatePalette,
5727 /*** Odd functions **/
5728 IWineD3DDeviceImpl_Init3D,
5729 IWineD3DDeviceImpl_Uninit3D,
5730 IWineD3DDeviceImpl_SetFullscreen,
5731 IWineD3DDeviceImpl_EnumDisplayModes,
5732 IWineD3DDeviceImpl_EvictManagedResources,
5733 IWineD3DDeviceImpl_GetAvailableTextureMem,
5734 IWineD3DDeviceImpl_GetBackBuffer,
5735 IWineD3DDeviceImpl_GetCreationParameters,
5736 IWineD3DDeviceImpl_GetDeviceCaps,
5737 IWineD3DDeviceImpl_GetDirect3D,
5738 IWineD3DDeviceImpl_GetDisplayMode,
5739 IWineD3DDeviceImpl_SetDisplayMode,
5740 IWineD3DDeviceImpl_GetHWND,
5741 IWineD3DDeviceImpl_SetHWND,
5742 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5743 IWineD3DDeviceImpl_GetRasterStatus,
5744 IWineD3DDeviceImpl_GetSwapChain,
5745 IWineD3DDeviceImpl_Reset,
5746 IWineD3DDeviceImpl_SetDialogBoxMode,
5747 IWineD3DDeviceImpl_SetCursorProperties,
5748 IWineD3DDeviceImpl_SetCursorPosition,
5749 IWineD3DDeviceImpl_ShowCursor,
5750 IWineD3DDeviceImpl_TestCooperativeLevel,
5751 /*** Getters and setters **/
5752 IWineD3DDeviceImpl_SetClipPlane,
5753 IWineD3DDeviceImpl_GetClipPlane,
5754 IWineD3DDeviceImpl_SetClipStatus,
5755 IWineD3DDeviceImpl_GetClipStatus,
5756 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5757 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5758 IWineD3DDeviceImpl_SetDepthStencilSurface,
5759 IWineD3DDeviceImpl_GetDepthStencilSurface,
5760 IWineD3DDeviceImpl_SetFVF,
5761 IWineD3DDeviceImpl_GetFVF,
5762 IWineD3DDeviceImpl_SetGammaRamp,
5763 IWineD3DDeviceImpl_GetGammaRamp,
5764 IWineD3DDeviceImpl_SetIndices,
5765 IWineD3DDeviceImpl_GetIndices,
5766 IWineD3DDeviceImpl_SetBasevertexIndex,
5767 IWineD3DDeviceImpl_SetLight,
5768 IWineD3DDeviceImpl_GetLight,
5769 IWineD3DDeviceImpl_SetLightEnable,
5770 IWineD3DDeviceImpl_GetLightEnable,
5771 IWineD3DDeviceImpl_SetMaterial,
5772 IWineD3DDeviceImpl_GetMaterial,
5773 IWineD3DDeviceImpl_SetNPatchMode,
5774 IWineD3DDeviceImpl_GetNPatchMode,
5775 IWineD3DDeviceImpl_SetPaletteEntries,
5776 IWineD3DDeviceImpl_GetPaletteEntries,
5777 IWineD3DDeviceImpl_SetPixelShader,
5778 IWineD3DDeviceImpl_GetPixelShader,
5779 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5780 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5781 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5782 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5783 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5784 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5785 IWineD3DDeviceImpl_SetRenderState,
5786 IWineD3DDeviceImpl_GetRenderState,
5787 IWineD3DDeviceImpl_SetRenderTarget,
5788 IWineD3DDeviceImpl_GetRenderTarget,
5789 IWineD3DDeviceImpl_SetFrontBackBuffers,
5790 IWineD3DDeviceImpl_SetSamplerState,
5791 IWineD3DDeviceImpl_GetSamplerState,
5792 IWineD3DDeviceImpl_SetScissorRect,
5793 IWineD3DDeviceImpl_GetScissorRect,
5794 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5795 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5796 IWineD3DDeviceImpl_SetStreamSource,
5797 IWineD3DDeviceImpl_GetStreamSource,
5798 IWineD3DDeviceImpl_SetStreamSourceFreq,
5799 IWineD3DDeviceImpl_GetStreamSourceFreq,
5800 IWineD3DDeviceImpl_SetTexture,
5801 IWineD3DDeviceImpl_GetTexture,
5802 IWineD3DDeviceImpl_SetTextureStageState,
5803 IWineD3DDeviceImpl_GetTextureStageState,
5804 IWineD3DDeviceImpl_SetTransform,
5805 IWineD3DDeviceImpl_GetTransform,
5806 IWineD3DDeviceImpl_SetVertexDeclaration,
5807 IWineD3DDeviceImpl_GetVertexDeclaration,
5808 IWineD3DDeviceImpl_SetVertexShader,
5809 IWineD3DDeviceImpl_GetVertexShader,
5810 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5811 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5812 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5813 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5814 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5815 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5816 IWineD3DDeviceImpl_SetViewport,
5817 IWineD3DDeviceImpl_GetViewport,
5818 IWineD3DDeviceImpl_MultiplyTransform,
5819 IWineD3DDeviceImpl_ValidateDevice,
5820 IWineD3DDeviceImpl_ProcessVertices,
5821 /*** State block ***/
5822 IWineD3DDeviceImpl_BeginStateBlock,
5823 IWineD3DDeviceImpl_EndStateBlock,
5824 /*** Scene management ***/
5825 IWineD3DDeviceImpl_BeginScene,
5826 IWineD3DDeviceImpl_EndScene,
5827 IWineD3DDeviceImpl_Present,
5828 IWineD3DDeviceImpl_Clear,
5829 /*** Drawing ***/
5830 IWineD3DDeviceImpl_DrawPrimitive,
5831 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5832 IWineD3DDeviceImpl_DrawPrimitiveUP,
5833 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5834 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5835 IWineD3DDeviceImpl_DrawRectPatch,
5836 IWineD3DDeviceImpl_DrawTriPatch,
5837 IWineD3DDeviceImpl_DeletePatch,
5838 IWineD3DDeviceImpl_ColorFill,
5839 IWineD3DDeviceImpl_UpdateTexture,
5840 IWineD3DDeviceImpl_UpdateSurface,
5841 IWineD3DDeviceImpl_GetFrontBufferData,
5842 /*** object tracking ***/
5843 IWineD3DDeviceImpl_ResourceReleased
5847 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5848 WINED3DRS_ALPHABLENDENABLE ,
5849 WINED3DRS_ALPHAFUNC ,
5850 WINED3DRS_ALPHAREF ,
5851 WINED3DRS_ALPHATESTENABLE ,
5852 WINED3DRS_BLENDOP ,
5853 WINED3DRS_COLORWRITEENABLE ,
5854 WINED3DRS_DESTBLEND ,
5855 WINED3DRS_DITHERENABLE ,
5856 WINED3DRS_FILLMODE ,
5857 WINED3DRS_FOGDENSITY ,
5858 WINED3DRS_FOGEND ,
5859 WINED3DRS_FOGSTART ,
5860 WINED3DRS_LASTPIXEL ,
5861 WINED3DRS_SHADEMODE ,
5862 WINED3DRS_SRCBLEND ,
5863 WINED3DRS_STENCILENABLE ,
5864 WINED3DRS_STENCILFAIL ,
5865 WINED3DRS_STENCILFUNC ,
5866 WINED3DRS_STENCILMASK ,
5867 WINED3DRS_STENCILPASS ,
5868 WINED3DRS_STENCILREF ,
5869 WINED3DRS_STENCILWRITEMASK ,
5870 WINED3DRS_STENCILZFAIL ,
5871 WINED3DRS_TEXTUREFACTOR ,
5872 WINED3DRS_WRAP0 ,
5873 WINED3DRS_WRAP1 ,
5874 WINED3DRS_WRAP2 ,
5875 WINED3DRS_WRAP3 ,
5876 WINED3DRS_WRAP4 ,
5877 WINED3DRS_WRAP5 ,
5878 WINED3DRS_WRAP6 ,
5879 WINED3DRS_WRAP7 ,
5880 WINED3DRS_ZENABLE ,
5881 WINED3DRS_ZFUNC ,
5882 WINED3DRS_ZWRITEENABLE
5885 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5886 WINED3DTSS_ADDRESSW ,
5887 WINED3DTSS_ALPHAARG0 ,
5888 WINED3DTSS_ALPHAARG1 ,
5889 WINED3DTSS_ALPHAARG2 ,
5890 WINED3DTSS_ALPHAOP ,
5891 WINED3DTSS_BUMPENVLOFFSET ,
5892 WINED3DTSS_BUMPENVLSCALE ,
5893 WINED3DTSS_BUMPENVMAT00 ,
5894 WINED3DTSS_BUMPENVMAT01 ,
5895 WINED3DTSS_BUMPENVMAT10 ,
5896 WINED3DTSS_BUMPENVMAT11 ,
5897 WINED3DTSS_COLORARG0 ,
5898 WINED3DTSS_COLORARG1 ,
5899 WINED3DTSS_COLORARG2 ,
5900 WINED3DTSS_COLOROP ,
5901 WINED3DTSS_RESULTARG ,
5902 WINED3DTSS_TEXCOORDINDEX ,
5903 WINED3DTSS_TEXTURETRANSFORMFLAGS
5906 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5907 WINED3DSAMP_ADDRESSU ,
5908 WINED3DSAMP_ADDRESSV ,
5909 WINED3DSAMP_ADDRESSW ,
5910 WINED3DSAMP_BORDERCOLOR ,
5911 WINED3DSAMP_MAGFILTER ,
5912 WINED3DSAMP_MINFILTER ,
5913 WINED3DSAMP_MIPFILTER ,
5914 WINED3DSAMP_MIPMAPLODBIAS ,
5915 WINED3DSAMP_MAXMIPLEVEL ,
5916 WINED3DSAMP_MAXANISOTROPY ,
5917 WINED3DSAMP_SRGBTEXTURE ,
5918 WINED3DSAMP_ELEMENTINDEX
5921 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5922 WINED3DRS_AMBIENT ,
5923 WINED3DRS_AMBIENTMATERIALSOURCE ,
5924 WINED3DRS_CLIPPING ,
5925 WINED3DRS_CLIPPLANEENABLE ,
5926 WINED3DRS_COLORVERTEX ,
5927 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5928 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5929 WINED3DRS_FOGDENSITY ,
5930 WINED3DRS_FOGEND ,
5931 WINED3DRS_FOGSTART ,
5932 WINED3DRS_FOGTABLEMODE ,
5933 WINED3DRS_FOGVERTEXMODE ,
5934 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5935 WINED3DRS_LIGHTING ,
5936 WINED3DRS_LOCALVIEWER ,
5937 WINED3DRS_MULTISAMPLEANTIALIAS ,
5938 WINED3DRS_MULTISAMPLEMASK ,
5939 WINED3DRS_NORMALIZENORMALS ,
5940 WINED3DRS_PATCHEDGESTYLE ,
5941 WINED3DRS_POINTSCALE_A ,
5942 WINED3DRS_POINTSCALE_B ,
5943 WINED3DRS_POINTSCALE_C ,
5944 WINED3DRS_POINTSCALEENABLE ,
5945 WINED3DRS_POINTSIZE ,
5946 WINED3DRS_POINTSIZE_MAX ,
5947 WINED3DRS_POINTSIZE_MIN ,
5948 WINED3DRS_POINTSPRITEENABLE ,
5949 WINED3DRS_RANGEFOGENABLE ,
5950 WINED3DRS_SPECULARMATERIALSOURCE ,
5951 WINED3DRS_TWEENFACTOR ,
5952 WINED3DRS_VERTEXBLEND
5955 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5956 WINED3DTSS_TEXCOORDINDEX ,
5957 WINED3DTSS_TEXTURETRANSFORMFLAGS
5960 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5961 WINED3DSAMP_DMAPOFFSET
5964 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5965 DWORD rep = StateTable[state].representative;
5966 DWORD idx;
5967 BYTE shift;
5968 UINT i;
5969 WineD3DContext *context;
5971 if(!rep) return;
5972 for(i = 0; i < This->numContexts; i++) {
5973 context = This->contexts[i];
5974 if(isStateDirty(context, rep)) continue;
5976 context->dirtyArray[context->numDirtyEntries++] = rep;
5977 idx = rep >> 5;
5978 shift = rep & 0x1f;
5979 context->isStateDirty[idx] |= (1 << shift);