wined3d: Instancing emulation.
[wine/multimedia.git] / dlls / wined3d / device.c
blob3376bf9e3aead192c560c9cfff0a048beb2ac6bc
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 & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
362 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
363 case D3DUSAGE_DYNAMIC:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage = GL_STREAM_DRAW_ARB;
366 break;
367 case D3DUSAGE_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 > D3DPRESENT_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 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle);
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(swapchain->backBuffer && swapchain->backBuffer[0]) {
1685 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1686 This->render_targets[0] = swapchain->backBuffer[0];
1687 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1689 else {
1690 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1691 This->render_targets[0] = swapchain->frontBuffer;
1692 This->lastActiveRenderTarget = swapchain->frontBuffer;
1694 IWineD3DSurface_AddRef(This->render_targets[0]);
1695 This->activeContext = swapchain->context;
1697 /* Depth Stencil support */
1698 This->stencilBufferTarget = This->depthStencilBuffer;
1699 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1700 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1702 if (NULL != This->stencilBufferTarget) {
1703 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1706 /* Set up some starting GL setup */
1707 ENTER_GL();
1709 * Initialize openGL extension related variables
1710 * with Default values
1713 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1714 /* Setup all the devices defaults */
1715 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1716 #if 0
1717 IWineD3DImpl_CheckGraphicsMemory();
1718 #endif
1720 /* Initialize our list of GLSL programs */
1721 list_init(&This->glsl_shader_progs);
1723 { /* Set a default viewport */
1724 WINED3DVIEWPORT vp;
1725 vp.X = 0;
1726 vp.Y = 0;
1727 vp.Width = *(pPresentationParameters->BackBufferWidth);
1728 vp.Height = *(pPresentationParameters->BackBufferHeight);
1729 vp.MinZ = 0.0f;
1730 vp.MaxZ = 1.0f;
1731 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1734 /* Initialize the current view state */
1735 This->view_ident = 1;
1736 This->contexts[0]->last_was_rhw = 0;
1737 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1738 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1739 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1740 LEAVE_GL();
1742 /* Clear the screen */
1743 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1745 This->d3d_initialized = TRUE;
1746 return WINED3D_OK;
1749 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1751 int sampler;
1752 uint i;
1753 TRACE("(%p)\n", This);
1755 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1757 /* Delete the pbuffer context if there is any */
1758 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1760 /* Delete the mouse cursor texture */
1761 if(This->cursorTexture) {
1762 ENTER_GL();
1763 glDeleteTextures(1, &This->cursorTexture);
1764 LEAVE_GL();
1765 This->cursorTexture = 0;
1768 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1769 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1772 /* Release the buffers (with sanity checks)*/
1773 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1774 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1775 if(This->depthStencilBuffer != This->stencilBufferTarget)
1776 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1778 This->stencilBufferTarget = NULL;
1780 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1781 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1782 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1784 TRACE("Setting rendertarget to NULL\n");
1785 This->render_targets[0] = NULL;
1787 if (This->depthStencilBuffer) {
1788 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1789 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1791 This->depthStencilBuffer = NULL;
1794 for(i=0; i < This->NumberOfSwapChains; i++) {
1795 TRACE("Releasing the implicit swapchain %d\n", i);
1796 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1797 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1801 HeapFree(GetProcessHeap(), 0, This->swapchains);
1802 This->swapchains = NULL;
1803 This->NumberOfSwapChains = 0;
1805 This->d3d_initialized = FALSE;
1806 return WINED3D_OK;
1809 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1811 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1813 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1814 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1815 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1816 * separately.
1818 This->ddraw_fullscreen = fullscreen;
1821 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
1822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1824 DEVMODEW DevModeW;
1825 int i;
1826 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
1828 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
1830 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
1831 /* Ignore some modes if a description was passed */
1832 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
1833 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
1834 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
1836 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
1838 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
1839 return D3D_OK;
1842 return D3D_OK;
1845 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1846 DEVMODEW devmode;
1847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1848 LONG ret;
1849 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1850 RECT clip_rc;
1852 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1854 /* Resize the screen even without a window:
1855 * The app could have unset it with SetCooperativeLevel, but not called
1856 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1857 * but we don't have any hwnd
1860 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1861 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1862 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1863 devmode.dmPelsWidth = pMode->Width;
1864 devmode.dmPelsHeight = pMode->Height;
1866 devmode.dmDisplayFrequency = pMode->RefreshRate;
1867 if (pMode->RefreshRate != 0) {
1868 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1871 /* Only change the mode if necessary */
1872 if( (This->ddraw_width == pMode->Width) &&
1873 (This->ddraw_height == pMode->Height) &&
1874 (This->ddraw_format == pMode->Format) &&
1875 (pMode->RefreshRate == 0) ) {
1876 return D3D_OK;
1879 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1880 if (ret != DISP_CHANGE_SUCCESSFUL) {
1881 if(devmode.dmDisplayFrequency != 0) {
1882 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1883 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1884 devmode.dmDisplayFrequency = 0;
1885 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1887 if(ret != DISP_CHANGE_SUCCESSFUL) {
1888 return DDERR_INVALIDMODE;
1892 /* Store the new values */
1893 This->ddraw_width = pMode->Width;
1894 This->ddraw_height = pMode->Height;
1895 This->ddraw_format = pMode->Format;
1897 /* Only do this with a window of course */
1898 if(This->ddraw_window)
1899 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1901 /* And finally clip mouse to our screen */
1902 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1903 ClipCursor(&clip_rc);
1905 return WINED3D_OK;
1908 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1910 *ppD3D= This->wineD3D;
1911 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1912 IWineD3D_AddRef(*ppD3D);
1913 return WINED3D_OK;
1916 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1917 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1918 * into the video ram as possible and seeing how many fit
1919 * you can also get the correct initial value from nvidia and ATI's driver via X
1920 * texture memory is video memory + AGP memory
1921 *******************/
1922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1923 static BOOL showfixmes = TRUE;
1924 if (showfixmes) {
1925 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1926 (wined3d_settings.emulated_textureram/(1024*1024)),
1927 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1928 showfixmes = FALSE;
1930 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1931 (wined3d_settings.emulated_textureram/(1024*1024)),
1932 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1933 /* return simulated texture memory left */
1934 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1939 /*****
1940 * Get / Set FVF
1941 *****/
1942 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1945 /* Update the current state block */
1946 This->updateStateBlock->changed.fvf = TRUE;
1947 This->updateStateBlock->set.fvf = TRUE;
1949 if(This->updateStateBlock->fvf == fvf) {
1950 TRACE("Application is setting the old fvf over, nothing to do\n");
1951 return WINED3D_OK;
1954 This->updateStateBlock->fvf = fvf;
1955 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1957 return WINED3D_OK;
1961 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1963 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1964 *pfvf = This->stateBlock->fvf;
1965 return WINED3D_OK;
1968 /*****
1969 * Get / Set Stream Source
1970 *****/
1971 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1973 IWineD3DVertexBuffer *oldSrc;
1975 if (StreamNumber >= MAX_STREAMS) {
1976 WARN("Stream out of range %d\n", StreamNumber);
1977 return WINED3DERR_INVALIDCALL;
1980 oldSrc = This->stateBlock->streamSource[StreamNumber];
1981 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1983 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1984 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1986 if(oldSrc == pStreamData &&
1987 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1988 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1989 TRACE("Application is setting the old values over, nothing to do\n");
1990 return WINED3D_OK;
1993 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1994 if (pStreamData) {
1995 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1996 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1999 /* Handle recording of state blocks */
2000 if (This->isRecordingState) {
2001 TRACE("Recording... not performing anything\n");
2002 return WINED3D_OK;
2005 /* Need to do a getParent and pass the reffs up */
2006 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2007 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2008 so for now, just count internally */
2009 if (pStreamData != NULL) {
2010 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2011 InterlockedIncrement(&vbImpl->bindCount);
2013 if (oldSrc != NULL) {
2014 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2017 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2019 return WINED3D_OK;
2022 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2024 UINT streamFlags;
2026 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2027 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2030 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2031 if (streamFlags) {
2032 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2033 FIXME("stream index data not supported\n");
2035 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2036 FIXME("stream instance data not supported\n");
2040 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2042 if (StreamNumber >= MAX_STREAMS) {
2043 WARN("Stream out of range %d\n", StreamNumber);
2044 return WINED3DERR_INVALIDCALL;
2046 *pStream = This->stateBlock->streamSource[StreamNumber];
2047 *pStride = This->stateBlock->streamStride[StreamNumber];
2048 if (pOffset) {
2049 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2052 if (*pStream != NULL) {
2053 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2055 return WINED3D_OK;
2058 /*Should be quite easy, just an extension of vertexdata
2059 ref...
2060 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2062 The divider is a bit odd though
2064 VertexOffset = StartVertex / Divider * StreamStride +
2065 VertexIndex / Divider * StreamStride + StreamOffset
2068 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2070 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2071 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2073 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2074 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2076 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2077 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2078 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2080 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2081 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2085 return WINED3D_OK;
2088 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2091 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2092 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2094 TRACE("(%p) : returning %d\n", This, *Divider);
2096 return WINED3D_OK;
2099 /*****
2100 * Get / Set & Multiply Transform
2101 *****/
2102 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2105 /* Most of this routine, comments included copied from ddraw tree initially: */
2106 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2108 /* Handle recording of state blocks */
2109 if (This->isRecordingState) {
2110 TRACE("Recording... not performing anything\n");
2111 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2112 This->updateStateBlock->set.transform[d3dts] = TRUE;
2113 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2114 return WINED3D_OK;
2118 * If the new matrix is the same as the current one,
2119 * we cut off any further processing. this seems to be a reasonable
2120 * optimization because as was noticed, some apps (warcraft3 for example)
2121 * tend towards setting the same matrix repeatedly for some reason.
2123 * From here on we assume that the new matrix is different, wherever it matters.
2125 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2126 TRACE("The app is setting the same matrix over again\n");
2127 return WINED3D_OK;
2128 } else {
2129 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2133 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2134 where ViewMat = Camera space, WorldMat = world space.
2136 In OpenGL, camera and world space is combined into GL_MODELVIEW
2137 matrix. The Projection matrix stay projection matrix.
2140 /* Capture the times we can just ignore the change for now */
2141 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2142 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2143 /* Handled by the state manager */
2146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2147 return WINED3D_OK;
2150 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2152 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2153 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2154 return WINED3D_OK;
2157 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2158 WINED3DMATRIX *mat = NULL;
2159 WINED3DMATRIX temp;
2161 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2162 * below means it will be recorded in a state block change, but it
2163 * works regardless where it is recorded.
2164 * If this is found to be wrong, change to StateBlock.
2166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2167 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2169 if (State < HIGHEST_TRANSFORMSTATE)
2171 mat = &This->updateStateBlock->transforms[State];
2172 } else {
2173 FIXME("Unhandled transform state!!\n");
2176 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2178 /* Apply change via set transform - will reapply to eg. lights this way */
2179 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2182 /*****
2183 * Get / Set Light
2184 *****/
2185 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2186 you can reference any indexes you want as long as that number max are enabled at any
2187 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2188 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2189 but when recording, just build a chain pretty much of commands to be replayed. */
2191 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2192 float rho;
2193 PLIGHTINFOEL *object = NULL;
2194 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2195 struct list *e;
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2198 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2200 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2201 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2202 if(object->OriginalIndex == Index) break;
2203 object = NULL;
2206 if(!object) {
2207 TRACE("Adding new light\n");
2208 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2209 if(!object) {
2210 ERR("Out of memory error when allocating a light\n");
2211 return E_OUTOFMEMORY;
2213 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2214 object->glIndex = -1;
2215 object->OriginalIndex = Index;
2216 object->changed = TRUE;
2219 /* Initialize the object */
2220 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,
2221 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2222 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2223 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2224 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2225 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2226 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2228 /* Save away the information */
2229 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2231 switch (pLight->Type) {
2232 case WINED3DLIGHT_POINT:
2233 /* Position */
2234 object->lightPosn[0] = pLight->Position.x;
2235 object->lightPosn[1] = pLight->Position.y;
2236 object->lightPosn[2] = pLight->Position.z;
2237 object->lightPosn[3] = 1.0f;
2238 object->cutoff = 180.0f;
2239 /* FIXME: Range */
2240 break;
2242 case WINED3DLIGHT_DIRECTIONAL:
2243 /* Direction */
2244 object->lightPosn[0] = -pLight->Direction.x;
2245 object->lightPosn[1] = -pLight->Direction.y;
2246 object->lightPosn[2] = -pLight->Direction.z;
2247 object->lightPosn[3] = 0.0;
2248 object->exponent = 0.0f;
2249 object->cutoff = 180.0f;
2250 break;
2252 case WINED3DLIGHT_SPOT:
2253 /* Position */
2254 object->lightPosn[0] = pLight->Position.x;
2255 object->lightPosn[1] = pLight->Position.y;
2256 object->lightPosn[2] = pLight->Position.z;
2257 object->lightPosn[3] = 1.0;
2259 /* Direction */
2260 object->lightDirn[0] = pLight->Direction.x;
2261 object->lightDirn[1] = pLight->Direction.y;
2262 object->lightDirn[2] = pLight->Direction.z;
2263 object->lightDirn[3] = 1.0;
2266 * opengl-ish and d3d-ish spot lights use too different models for the
2267 * light "intensity" as a function of the angle towards the main light direction,
2268 * so we only can approximate very roughly.
2269 * however spot lights are rather rarely used in games (if ever used at all).
2270 * furthermore if still used, probably nobody pays attention to such details.
2272 if (pLight->Falloff == 0) {
2273 rho = 6.28f;
2274 } else {
2275 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2277 if (rho < 0.0001) rho = 0.0001f;
2278 object->exponent = -0.3/log(cos(rho/2));
2279 if (object->exponent > 128.0) {
2280 object->exponent = 128.0;
2282 object->cutoff = pLight->Phi*90/M_PI;
2284 /* FIXME: Range */
2285 break;
2287 default:
2288 FIXME("Unrecognized light type %d\n", pLight->Type);
2291 /* Update the live definitions if the light is currently assigned a glIndex */
2292 if (object->glIndex != -1 && !This->isRecordingState) {
2293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2295 return WINED3D_OK;
2298 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2299 PLIGHTINFOEL *lightInfo = NULL;
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2301 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2302 struct list *e;
2303 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2305 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2306 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2307 if(lightInfo->OriginalIndex == Index) break;
2308 lightInfo = NULL;
2311 if (lightInfo == NULL) {
2312 TRACE("Light information requested but light not defined\n");
2313 return WINED3DERR_INVALIDCALL;
2316 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2317 return WINED3D_OK;
2320 /*****
2321 * Get / Set Light Enable
2322 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2323 *****/
2324 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2325 PLIGHTINFOEL *lightInfo = NULL;
2326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2327 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2328 struct list *e;
2329 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2331 /* Tests show true = 128...not clear why */
2332 Enable = Enable? 128: 0;
2334 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2335 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2336 if(lightInfo->OriginalIndex == Index) break;
2337 lightInfo = NULL;
2339 TRACE("Found light: %p\n", lightInfo);
2341 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2342 if (lightInfo == NULL) {
2344 TRACE("Light enabled requested but light not defined, so defining one!\n");
2345 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2347 /* Search for it again! Should be fairly quick as near head of list */
2348 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2349 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2350 if(lightInfo->OriginalIndex == Index) break;
2351 lightInfo = NULL;
2353 if (lightInfo == NULL) {
2354 FIXME("Adding default lights has failed dismally\n");
2355 return WINED3DERR_INVALIDCALL;
2359 lightInfo->enabledChanged = TRUE;
2360 if(!Enable) {
2361 if(lightInfo->glIndex != -1) {
2362 if(!This->isRecordingState) {
2363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2366 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2367 lightInfo->glIndex = -1;
2368 } else {
2369 TRACE("Light already disabled, nothing to do\n");
2371 } else {
2372 if (lightInfo->glIndex != -1) {
2373 /* nop */
2374 TRACE("Nothing to do as light was enabled\n");
2375 } else {
2376 int i;
2377 /* Find a free gl light */
2378 for(i = 0; i < This->maxConcurrentLights; i++) {
2379 if(This->stateBlock->activeLights[i] == NULL) {
2380 This->stateBlock->activeLights[i] = lightInfo;
2381 lightInfo->glIndex = i;
2382 break;
2385 if(lightInfo->glIndex == -1) {
2386 ERR("Too many concurrently active lights\n");
2387 return WINED3DERR_INVALIDCALL;
2390 /* i == lightInfo->glIndex */
2391 if(!This->isRecordingState) {
2392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2397 return WINED3D_OK;
2400 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2402 PLIGHTINFOEL *lightInfo = NULL;
2403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2404 struct list *e;
2405 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2406 TRACE("(%p) : for idx(%d)\n", This, Index);
2408 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2409 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2410 if(lightInfo->OriginalIndex == Index) break;
2411 lightInfo = NULL;
2414 if (lightInfo == NULL) {
2415 TRACE("Light enabled state requested but light not defined\n");
2416 return WINED3DERR_INVALIDCALL;
2418 /* true is 128 according to SetLightEnable */
2419 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2420 return WINED3D_OK;
2423 /*****
2424 * Get / Set Clip Planes
2425 *****/
2426 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2428 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2430 /* Validate Index */
2431 if (Index >= GL_LIMITS(clipplanes)) {
2432 TRACE("Application has requested clipplane this device doesn't support\n");
2433 return WINED3DERR_INVALIDCALL;
2436 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2437 This->updateStateBlock->set.clipplane[Index] = TRUE;
2438 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2439 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2440 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2441 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2443 /* Handle recording of state blocks */
2444 if (This->isRecordingState) {
2445 TRACE("Recording... not performing anything\n");
2446 return WINED3D_OK;
2449 /* Apply it */
2451 ENTER_GL();
2453 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2454 glMatrixMode(GL_MODELVIEW);
2455 glPushMatrix();
2456 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2458 TRACE("Clipplane [%f,%f,%f,%f]\n",
2459 This->updateStateBlock->clipplane[Index][0],
2460 This->updateStateBlock->clipplane[Index][1],
2461 This->updateStateBlock->clipplane[Index][2],
2462 This->updateStateBlock->clipplane[Index][3]);
2463 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2464 checkGLcall("glClipPlane");
2466 glPopMatrix();
2467 LEAVE_GL();
2469 return WINED3D_OK;
2472 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2474 TRACE("(%p) : for idx %d\n", This, Index);
2476 /* Validate Index */
2477 if (Index >= GL_LIMITS(clipplanes)) {
2478 TRACE("Application has requested clipplane this device doesn't support\n");
2479 return WINED3DERR_INVALIDCALL;
2482 pPlane[0] = This->stateBlock->clipplane[Index][0];
2483 pPlane[1] = This->stateBlock->clipplane[Index][1];
2484 pPlane[2] = This->stateBlock->clipplane[Index][2];
2485 pPlane[3] = This->stateBlock->clipplane[Index][3];
2486 return WINED3D_OK;
2489 /*****
2490 * Get / Set Clip Plane Status
2491 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2492 *****/
2493 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 FIXME("(%p) : stub\n", This);
2496 if (NULL == pClipStatus) {
2497 return WINED3DERR_INVALIDCALL;
2499 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2500 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2501 return WINED3D_OK;
2504 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 FIXME("(%p) : stub\n", This);
2507 if (NULL == pClipStatus) {
2508 return WINED3DERR_INVALIDCALL;
2510 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2511 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2512 return WINED3D_OK;
2515 /*****
2516 * Get / Set Material
2517 *****/
2518 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 This->updateStateBlock->changed.material = TRUE;
2522 This->updateStateBlock->set.material = TRUE;
2523 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2525 /* Handle recording of state blocks */
2526 if (This->isRecordingState) {
2527 TRACE("Recording... not performing anything\n");
2528 return WINED3D_OK;
2531 ENTER_GL();
2532 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2533 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2534 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2535 pMaterial->Ambient.b, pMaterial->Ambient.a);
2536 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2537 pMaterial->Specular.b, pMaterial->Specular.a);
2538 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2539 pMaterial->Emissive.b, pMaterial->Emissive.a);
2540 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2542 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2543 checkGLcall("glMaterialfv(GL_AMBIENT)");
2544 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2545 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2547 /* Only change material color if specular is enabled, otherwise it is set to black */
2548 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2549 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2550 checkGLcall("glMaterialfv(GL_SPECULAR");
2551 } else {
2552 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2553 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2554 checkGLcall("glMaterialfv(GL_SPECULAR");
2556 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2557 checkGLcall("glMaterialfv(GL_EMISSION)");
2558 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2559 checkGLcall("glMaterialf(GL_SHININESS");
2561 LEAVE_GL();
2562 return WINED3D_OK;
2565 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2567 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2568 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2569 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2570 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2571 pMaterial->Ambient.b, pMaterial->Ambient.a);
2572 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2573 pMaterial->Specular.b, pMaterial->Specular.a);
2574 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2575 pMaterial->Emissive.b, pMaterial->Emissive.a);
2576 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2578 return WINED3D_OK;
2581 /*****
2582 * Get / Set Indices
2583 *****/
2584 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2585 UINT BaseVertexIndex) {
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2587 IWineD3DIndexBuffer *oldIdxs;
2588 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2590 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2591 oldIdxs = This->updateStateBlock->pIndexData;
2593 This->updateStateBlock->changed.indices = TRUE;
2594 This->updateStateBlock->set.indices = TRUE;
2595 This->updateStateBlock->pIndexData = pIndexData;
2596 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2598 /* Handle recording of state blocks */
2599 if (This->isRecordingState) {
2600 TRACE("Recording... not performing anything\n");
2601 return WINED3D_OK;
2604 /* So far only the base vertex index is tracked */
2605 if(BaseVertexIndex != oldBaseIndex) {
2606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2608 return WINED3D_OK;
2611 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 *ppIndexData = This->stateBlock->pIndexData;
2616 /* up ref count on ppindexdata */
2617 if (*ppIndexData) {
2618 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2619 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2620 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2621 }else{
2622 TRACE("(%p) No index data set\n", This);
2624 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2626 return WINED3D_OK;
2629 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2630 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p)->(%d)\n", This, BaseIndex);
2634 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2635 TRACE("Application is setting the old value over, nothing to do\n");
2636 return WINED3D_OK;
2639 This->updateStateBlock->baseVertexIndex = BaseIndex;
2641 if (This->isRecordingState) {
2642 TRACE("Recording... not performing anything\n");
2643 return WINED3D_OK;
2645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2646 return WINED3D_OK;
2649 /*****
2650 * Get / Set Viewports
2651 *****/
2652 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2655 TRACE("(%p)\n", This);
2656 This->updateStateBlock->changed.viewport = TRUE;
2657 This->updateStateBlock->set.viewport = TRUE;
2658 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2660 /* Handle recording of state blocks */
2661 if (This->isRecordingState) {
2662 TRACE("Recording... not performing anything\n");
2663 return WINED3D_OK;
2666 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2667 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2670 return WINED3D_OK;
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 TRACE("(%p)\n", This);
2677 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2678 return WINED3D_OK;
2681 /*****
2682 * Get / Set Render States
2683 * TODO: Verify against dx9 definitions
2684 *****/
2685 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2688 DWORD oldValue = This->stateBlock->renderState[State];
2690 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2692 This->updateStateBlock->changed.renderState[State] = TRUE;
2693 This->updateStateBlock->set.renderState[State] = TRUE;
2694 This->updateStateBlock->renderState[State] = Value;
2696 /* Handle recording of state blocks */
2697 if (This->isRecordingState) {
2698 TRACE("Recording... not performing anything\n");
2699 return WINED3D_OK;
2702 /* Compared here and not before the assignment to allow proper stateblock recording */
2703 if(Value == oldValue) {
2704 TRACE("Application is setting the old value over, nothing to do\n");
2705 } else {
2706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2709 return WINED3D_OK;
2712 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2715 *pValue = This->stateBlock->renderState[State];
2716 return WINED3D_OK;
2719 /*****
2720 * Get / Set Sampler States
2721 * TODO: Verify against dx9 definitions
2722 *****/
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2729 * SetSampler is designed to allow for more than the standard up to 8 textures
2730 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2731 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2733 * http://developer.nvidia.com/object/General_FAQ.html#t6
2735 * There are two new settings for GForce
2736 * the sampler one:
2737 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2738 * and the texture one:
2739 * GL_MAX_TEXTURE_COORDS_ARB.
2740 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2741 ******************/
2742 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2743 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
2744 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2745 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
2746 return WINED3DERR_INVALIDCALL;
2749 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2750 debug_d3dsamplerstate(Type), Type, Value);
2751 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2752 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2753 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2755 /* Handle recording of state blocks */
2756 if (This->isRecordingState) {
2757 TRACE("Recording... not performing anything\n");
2758 return WINED3D_OK;
2761 if(oldValue == Value) {
2762 TRACE("Application is setting the old value over, nothing to do\n");
2763 return WINED3D_OK;
2766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2768 return WINED3D_OK;
2771 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 /** TODO: check that sampler is in range **/
2774 *Value = This->stateBlock->samplerState[Sampler][Type];
2775 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2777 return WINED3D_OK;
2780 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 RECT windowRect;
2783 UINT winHeight;
2785 This->updateStateBlock->set.scissorRect = TRUE;
2786 This->updateStateBlock->changed.scissorRect = TRUE;
2787 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2789 if(This->isRecordingState) {
2790 TRACE("Recording... not performing anything\n");
2791 return WINED3D_OK;
2794 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
2795 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2796 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2798 winHeight = windowRect.bottom - windowRect.top;
2799 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
2800 pRect->right - pRect->left, pRect->bottom - pRect->top);
2801 ENTER_GL();
2802 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
2803 checkGLcall("glScissor");
2804 LEAVE_GL();
2806 return WINED3D_OK;
2809 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2812 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2813 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2814 return WINED3D_OK;
2817 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2819 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2821 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2823 This->updateStateBlock->vertexDecl = pDecl;
2824 This->updateStateBlock->changed.vertexDecl = TRUE;
2825 This->updateStateBlock->set.vertexDecl = TRUE;
2827 if (This->isRecordingState) {
2828 TRACE("Recording... not performing anything\n");
2829 return WINED3D_OK;
2830 } else if(pDecl == oldDecl) {
2831 /* Checked after the assignment to allow proper stateblock recording */
2832 TRACE("Application is setting the old declaration over, nothing to do\n");
2833 return WINED3D_OK;
2836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2837 return WINED3D_OK;
2840 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2843 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2845 *ppDecl = This->stateBlock->vertexDecl;
2846 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2847 return WINED3D_OK;
2850 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2854 This->updateStateBlock->vertexShader = pShader;
2855 This->updateStateBlock->changed.vertexShader = TRUE;
2856 This->updateStateBlock->set.vertexShader = TRUE;
2858 if (This->isRecordingState) {
2859 TRACE("Recording... not performing anything\n");
2860 return WINED3D_OK;
2861 } else if(oldShader == pShader) {
2862 /* Checked here to allow proper stateblock recording */
2863 TRACE("App is setting the old shader over, nothing to do\n");
2864 return WINED3D_OK;
2867 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2871 return WINED3D_OK;
2874 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2877 if (NULL == ppShader) {
2878 return WINED3DERR_INVALIDCALL;
2880 *ppShader = This->stateBlock->vertexShader;
2881 if( NULL != *ppShader)
2882 IWineD3DVertexShader_AddRef(*ppShader);
2884 TRACE("(%p) : returning %p\n", This, *ppShader);
2885 return WINED3D_OK;
2888 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2889 IWineD3DDevice *iface,
2890 UINT start,
2891 CONST BOOL *srcData,
2892 UINT count) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 int i, cnt = min(count, MAX_CONST_B - start);
2897 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2898 iface, srcData, start, count);
2900 if (srcData == NULL || cnt < 0)
2901 return WINED3DERR_INVALIDCALL;
2903 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2904 for (i = 0; i < cnt; i++)
2905 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2907 for (i = start; i < cnt + start; ++i) {
2908 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2909 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2914 return WINED3D_OK;
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2918 IWineD3DDevice *iface,
2919 UINT start,
2920 BOOL *dstData,
2921 UINT count) {
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 int cnt = min(count, MAX_CONST_B - start);
2926 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2927 iface, dstData, start, count);
2929 if (dstData == NULL || cnt < 0)
2930 return WINED3DERR_INVALIDCALL;
2932 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2937 IWineD3DDevice *iface,
2938 UINT start,
2939 CONST int *srcData,
2940 UINT count) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 int i, cnt = min(count, MAX_CONST_I - start);
2945 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2946 iface, srcData, start, count);
2948 if (srcData == NULL || cnt < 0)
2949 return WINED3DERR_INVALIDCALL;
2951 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2952 for (i = 0; i < cnt; i++)
2953 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2954 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2956 for (i = start; i < cnt + start; ++i) {
2957 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2958 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2963 return WINED3D_OK;
2966 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2967 IWineD3DDevice *iface,
2968 UINT start,
2969 int *dstData,
2970 UINT count) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 int cnt = min(count, MAX_CONST_I - start);
2975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2976 iface, dstData, start, count);
2978 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2979 return WINED3DERR_INVALIDCALL;
2981 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2982 return WINED3D_OK;
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2986 IWineD3DDevice *iface,
2987 UINT start,
2988 CONST float *srcData,
2989 UINT count) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2995 iface, srcData, start, count);
2997 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
2998 return WINED3DERR_INVALIDCALL;
3000 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3001 for (i = 0; i < cnt; i++)
3002 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3003 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3005 for (i = start; i < cnt + start; ++i) {
3006 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3007 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3008 ptr->idx = i;
3009 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3010 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3012 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3015 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3017 return WINED3D_OK;
3020 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3021 IWineD3DDevice *iface,
3022 UINT start,
3023 float *dstData,
3024 UINT count) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3027 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3029 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3030 iface, dstData, start, count);
3032 if (dstData == NULL || cnt < 0)
3033 return WINED3DERR_INVALIDCALL;
3035 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3036 return WINED3D_OK;
3039 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3040 DWORD i;
3041 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3046 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3047 DWORD i, tex;
3048 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3049 * it is never called.
3051 * Rules are:
3052 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3053 * that would be really messy and require shader recompilation
3054 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3055 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3056 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3057 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3059 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3060 if(This->oneToOneTexUnitMap) {
3061 TRACE("Not touching 1:1 map\n");
3062 return;
3064 TRACE("Restoring 1:1 texture unit mapping\n");
3065 /* Restore a 1:1 mapping */
3066 for(i = 0; i < MAX_SAMPLERS; i++) {
3067 if(This->texUnitMap[i] != i) {
3068 This->texUnitMap[i] = i;
3069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3070 markTextureStagesDirty(This, i);
3073 This->oneToOneTexUnitMap = TRUE;
3074 return;
3075 } else {
3076 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3077 * First, see if we can succeed at all
3079 tex = 0;
3080 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3081 if(This->stateBlock->textures[i] == NULL) tex++;
3084 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3085 FIXME("Too many bound textures to support the combiner settings\n");
3086 return;
3089 /* Now work out the mapping */
3090 tex = 0;
3091 This->oneToOneTexUnitMap = FALSE;
3092 WARN("Non 1:1 mapping UNTESTED!\n");
3093 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3094 /* Skip NULL textures */
3095 if (!This->stateBlock->textures[i]) {
3096 /* Map to -1, so the check below doesn't fail if a non-NULL
3097 * texture is set on this stage */
3098 TRACE("Mapping texture stage %d to -1\n", i);
3099 This->texUnitMap[i] = -1;
3101 continue;
3104 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3105 if(This->texUnitMap[i] != tex) {
3106 This->texUnitMap[i] = tex;
3107 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3108 markTextureStagesDirty(This, i);
3111 ++tex;
3116 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3119 This->updateStateBlock->pixelShader = pShader;
3120 This->updateStateBlock->changed.pixelShader = TRUE;
3121 This->updateStateBlock->set.pixelShader = TRUE;
3123 /* Handle recording of state blocks */
3124 if (This->isRecordingState) {
3125 TRACE("Recording... not performing anything\n");
3128 if (This->isRecordingState) {
3129 TRACE("Recording... not performing anything\n");
3130 return WINED3D_OK;
3133 if(pShader == oldShader) {
3134 TRACE("App is setting the old pixel shader over, nothing to do\n");
3135 return WINED3D_OK;
3138 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3141 /* Rebuild the texture unit mapping if nvrc's are supported */
3142 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3143 IWineD3DDeviceImpl_FindTexUnitMap(This);
3146 return WINED3D_OK;
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 if (NULL == ppShader) {
3153 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3154 return WINED3DERR_INVALIDCALL;
3157 *ppShader = This->stateBlock->pixelShader;
3158 if (NULL != *ppShader) {
3159 IWineD3DPixelShader_AddRef(*ppShader);
3161 TRACE("(%p) : returning %p\n", This, *ppShader);
3162 return WINED3D_OK;
3165 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3166 IWineD3DDevice *iface,
3167 UINT start,
3168 CONST BOOL *srcData,
3169 UINT count) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 int i, cnt = min(count, MAX_CONST_B - start);
3174 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3175 iface, srcData, start, count);
3177 if (srcData == NULL || cnt < 0)
3178 return WINED3DERR_INVALIDCALL;
3180 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3181 for (i = 0; i < cnt; i++)
3182 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3184 for (i = start; i < cnt + start; ++i) {
3185 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3186 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3191 return WINED3D_OK;
3194 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3195 IWineD3DDevice *iface,
3196 UINT start,
3197 BOOL *dstData,
3198 UINT count) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 int cnt = min(count, MAX_CONST_B - start);
3203 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3204 iface, dstData, start, count);
3206 if (dstData == NULL || cnt < 0)
3207 return WINED3DERR_INVALIDCALL;
3209 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3210 return WINED3D_OK;
3213 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3214 IWineD3DDevice *iface,
3215 UINT start,
3216 CONST int *srcData,
3217 UINT count) {
3219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 int i, cnt = min(count, MAX_CONST_I - start);
3222 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3223 iface, srcData, start, count);
3225 if (srcData == NULL || cnt < 0)
3226 return WINED3DERR_INVALIDCALL;
3228 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3229 for (i = 0; i < cnt; i++)
3230 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3231 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3233 for (i = start; i < cnt + start; ++i) {
3234 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3235 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3240 return WINED3D_OK;
3243 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3244 IWineD3DDevice *iface,
3245 UINT start,
3246 int *dstData,
3247 UINT count) {
3249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3250 int cnt = min(count, MAX_CONST_I - start);
3252 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3253 iface, dstData, start, count);
3255 if (dstData == NULL || cnt < 0)
3256 return WINED3DERR_INVALIDCALL;
3258 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3259 return WINED3D_OK;
3262 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3263 IWineD3DDevice *iface,
3264 UINT start,
3265 CONST float *srcData,
3266 UINT count) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3271 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3272 iface, srcData, start, count);
3274 if (srcData == NULL || cnt < 0)
3275 return WINED3DERR_INVALIDCALL;
3277 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3278 for (i = 0; i < cnt; i++)
3279 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3280 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3282 for (i = start; i < cnt + start; ++i) {
3283 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3284 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3285 ptr->idx = i;
3286 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3287 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3289 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3298 IWineD3DDevice *iface,
3299 UINT start,
3300 float *dstData,
3301 UINT count) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3306 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3307 iface, dstData, start, count);
3309 if (dstData == NULL || cnt < 0)
3310 return WINED3DERR_INVALIDCALL;
3312 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3313 return WINED3D_OK;
3316 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3317 static HRESULT
3318 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3319 char *dest_ptr, *dest_conv = NULL;
3320 unsigned int i;
3321 DWORD DestFVF = dest->fvf;
3322 WINED3DVIEWPORT vp;
3323 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3324 BOOL doClip;
3325 int numTextures;
3327 if (SrcFVF & WINED3DFVF_NORMAL) {
3328 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3331 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3332 ERR("Source has no position mask\n");
3333 return WINED3DERR_INVALIDCALL;
3336 /* We might access VBOs from this code, so hold the lock */
3337 ENTER_GL();
3339 if (dest->resource.allocatedMemory == NULL) {
3340 /* This may happen if we do direct locking into a vbo. Unlikely,
3341 * but theoretically possible(ddraw processvertices test)
3343 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3344 if(!dest->resource.allocatedMemory) {
3345 LEAVE_GL();
3346 ERR("Out of memory\n");
3347 return E_OUTOFMEMORY;
3349 if(dest->vbo) {
3350 void *src;
3351 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3352 checkGLcall("glBindBufferARB");
3353 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3354 if(src) {
3355 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3357 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3358 checkGLcall("glUnmapBufferARB");
3362 /* Get a pointer into the destination vbo(create one if none exists) and
3363 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3365 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3366 CreateVBO(dest);
3369 if(dest->vbo) {
3370 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3371 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3372 if(!dest_conv) {
3373 ERR("glMapBuffer failed\n");
3374 /* Continue without storing converted vertices */
3378 /* Should I clip?
3379 * a) WINED3DRS_CLIPPING is enabled
3380 * b) WINED3DVOP_CLIP is passed
3382 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3383 static BOOL warned = FALSE;
3385 * The clipping code is not quite correct. Some things need
3386 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3387 * so disable clipping for now.
3388 * (The graphics in Half-Life are broken, and my processvertices
3389 * test crashes with IDirect3DDevice3)
3390 doClip = TRUE;
3392 doClip = FALSE;
3393 if(!warned) {
3394 warned = TRUE;
3395 FIXME("Clipping is broken and disabled for now\n");
3397 } else doClip = FALSE;
3398 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3399 if(dest_conv) {
3400 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3403 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3404 WINED3DTS_VIEW,
3405 &view_mat);
3406 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3407 WINED3DTS_PROJECTION,
3408 &proj_mat);
3409 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3410 WINED3DTS_WORLDMATRIX(0),
3411 &world_mat);
3413 TRACE("View mat:\n");
3414 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);
3415 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);
3416 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);
3417 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);
3419 TRACE("Proj mat:\n");
3420 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);
3421 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);
3422 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);
3423 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);
3425 TRACE("World mat:\n");
3426 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);
3427 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);
3428 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);
3429 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);
3431 /* Get the viewport */
3432 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3433 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3434 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3436 multiply_matrix(&mat,&view_mat,&world_mat);
3437 multiply_matrix(&mat,&proj_mat,&mat);
3439 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3441 for (i = 0; i < dwCount; i+= 1) {
3442 unsigned int tex_index;
3444 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3445 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3446 /* The position first */
3447 float *p =
3448 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3449 float x, y, z, rhw;
3450 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3452 /* Multiplication with world, view and projection matrix */
3453 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);
3454 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);
3455 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);
3456 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);
3458 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3460 /* WARNING: The following things are taken from d3d7 and were not yet checked
3461 * against d3d8 or d3d9!
3464 /* Clipping conditions: From
3465 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3467 * A vertex is clipped if it does not match the following requirements
3468 * -rhw < x <= rhw
3469 * -rhw < y <= rhw
3470 * 0 < z <= rhw
3471 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3473 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3474 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3478 if( !doClip ||
3479 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3480 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3481 ( rhw > eps ) ) ) {
3483 /* "Normal" viewport transformation (not clipped)
3484 * 1) The values are divided by rhw
3485 * 2) The y axis is negative, so multiply it with -1
3486 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3487 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3488 * 4) Multiply x with Width/2 and add Width/2
3489 * 5) The same for the height
3490 * 6) Add the viewpoint X and Y to the 2D coordinates and
3491 * The minimum Z value to z
3492 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3494 * Well, basically it's simply a linear transformation into viewport
3495 * coordinates
3498 x /= rhw;
3499 y /= rhw;
3500 z /= rhw;
3502 y *= -1;
3504 x *= vp.Width / 2;
3505 y *= vp.Height / 2;
3506 z *= vp.MaxZ - vp.MinZ;
3508 x += vp.Width / 2 + vp.X;
3509 y += vp.Height / 2 + vp.Y;
3510 z += vp.MinZ;
3512 rhw = 1 / rhw;
3513 } else {
3514 /* That vertex got clipped
3515 * Contrary to OpenGL it is not dropped completely, it just
3516 * undergoes a different calculation.
3518 TRACE("Vertex got clipped\n");
3519 x += rhw;
3520 y += rhw;
3522 x /= 2;
3523 y /= 2;
3525 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3526 * outside of the main vertex buffer memory. That needs some more
3527 * investigation...
3531 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3534 ( (float *) dest_ptr)[0] = x;
3535 ( (float *) dest_ptr)[1] = y;
3536 ( (float *) dest_ptr)[2] = z;
3537 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3539 dest_ptr += 3 * sizeof(float);
3541 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3542 dest_ptr += sizeof(float);
3545 if(dest_conv) {
3546 float w = 1 / rhw;
3547 ( (float *) dest_conv)[0] = x * w;
3548 ( (float *) dest_conv)[1] = y * w;
3549 ( (float *) dest_conv)[2] = z * w;
3550 ( (float *) dest_conv)[3] = w;
3552 dest_conv += 3 * sizeof(float);
3554 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3555 dest_conv += sizeof(float);
3559 if (DestFVF & WINED3DFVF_PSIZE) {
3560 dest_ptr += sizeof(DWORD);
3561 if(dest_conv) dest_conv += sizeof(DWORD);
3563 if (DestFVF & WINED3DFVF_NORMAL) {
3564 float *normal =
3565 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3566 /* AFAIK this should go into the lighting information */
3567 FIXME("Didn't expect the destination to have a normal\n");
3568 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3569 if(dest_conv) {
3570 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3574 if (DestFVF & WINED3DFVF_DIFFUSE) {
3575 DWORD *color_d =
3576 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3577 if(!color_d) {
3578 static BOOL warned = FALSE;
3580 if(!warned) {
3581 ERR("No diffuse color in source, but destination has one\n");
3582 warned = TRUE;
3585 *( (DWORD *) dest_ptr) = 0xffffffff;
3586 dest_ptr += sizeof(DWORD);
3588 if(dest_conv) {
3589 *( (DWORD *) dest_conv) = 0xffffffff;
3590 dest_conv += sizeof(DWORD);
3593 else {
3594 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3595 if(dest_conv) {
3596 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3597 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3598 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3599 dest_conv += sizeof(DWORD);
3604 if (DestFVF & WINED3DFVF_SPECULAR) {
3605 /* What's the color value in the feedback buffer? */
3606 DWORD *color_s =
3607 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3608 if(!color_s) {
3609 static BOOL warned = FALSE;
3611 if(!warned) {
3612 ERR("No specular color in source, but destination has one\n");
3613 warned = TRUE;
3616 *( (DWORD *) dest_ptr) = 0xFF000000;
3617 dest_ptr += sizeof(DWORD);
3619 if(dest_conv) {
3620 *( (DWORD *) dest_conv) = 0xFF000000;
3621 dest_conv += sizeof(DWORD);
3624 else {
3625 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3626 if(dest_conv) {
3627 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3628 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3629 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3630 dest_conv += sizeof(DWORD);
3635 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3636 float *tex_coord =
3637 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3638 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3639 if(!tex_coord) {
3640 ERR("No source texture, but destination requests one\n");
3641 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3642 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3644 else {
3645 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3646 if(dest_conv) {
3647 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3653 if(dest_conv) {
3654 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3655 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3658 LEAVE_GL();
3660 return WINED3D_OK;
3662 #undef copy_and_next
3664 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3666 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3667 WineDirect3DVertexStridedData strided;
3668 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3670 if (!SrcImpl) {
3671 WARN("NULL source vertex buffer\n");
3672 return WINED3DERR_INVALIDCALL;
3674 /* We don't need the source vbo because this buffer is only used as
3675 * a source for ProcessVertices. Avoid wasting resources by converting the
3676 * buffer and loading the VBO
3678 if(SrcImpl->vbo) {
3679 TRACE("Releasing the source vbo, it won't be needed\n");
3681 if(!SrcImpl->resource.allocatedMemory) {
3682 /* Rescue the data from the buffer */
3683 void *src;
3684 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3685 if(!SrcImpl->resource.allocatedMemory) {
3686 ERR("Out of memory\n");
3687 return E_OUTOFMEMORY;
3690 ENTER_GL();
3691 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3692 checkGLcall("glBindBufferARB");
3694 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3695 if(src) {
3696 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3699 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3700 checkGLcall("glUnmapBufferARB");
3701 } else {
3702 ENTER_GL();
3705 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3706 checkGLcall("glBindBufferARB");
3707 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3708 checkGLcall("glDeleteBuffersARB");
3709 LEAVE_GL();
3711 SrcImpl->vbo = 0;
3714 memset(&strided, 0, sizeof(strided));
3715 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3717 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3720 /*****
3721 * Get / Set Texture Stage States
3722 * TODO: Verify against dx9 definitions
3723 *****/
3724 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3726 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3728 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3730 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3732 /* Reject invalid texture units */
3733 if (Stage >= GL_LIMITS(texture_stages)) {
3734 TRACE("Attempt to access invalid texture rejected\n");
3735 return WINED3DERR_INVALIDCALL;
3738 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3739 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3740 This->updateStateBlock->textureState[Stage][Type] = Value;
3742 if (This->isRecordingState) {
3743 TRACE("Recording... not performing anything\n");
3744 return WINED3D_OK;
3747 /* Checked after the assignments to allow proper stateblock recording */
3748 if(oldValue == Value) {
3749 TRACE("App is setting the old value over, nothing to do\n");
3750 return WINED3D_OK;
3753 if(Stage > This->stateBlock->lowest_disabled_stage &&
3754 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3755 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3756 * Changes in other states are important on disabled stages too
3758 return WINED3D_OK;
3761 if(Type == WINED3DTSS_COLOROP) {
3762 int i;
3764 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3765 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3766 * they have to be disabled
3768 * The current stage is dirtified below.
3770 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3771 TRACE("Additionally dirtifying stage %d\n", i);
3772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3774 This->stateBlock->lowest_disabled_stage = Stage;
3775 TRACE("New lowest disabled: %d\n", Stage);
3776 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3777 /* Previously disabled stage enabled. Stages above it may need enabling
3778 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3779 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3781 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3784 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3785 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3786 break;
3788 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3791 This->stateBlock->lowest_disabled_stage = i;
3792 TRACE("New lowest disabled: %d\n", i);
3794 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3795 /* TODO: Built a stage -> texture unit mapping for register combiners */
3799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3801 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3802 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3803 * will call FindTexUnitMap too.
3805 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3806 IWineD3DDeviceImpl_FindTexUnitMap(This);
3808 return WINED3D_OK;
3811 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3813 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3814 *pValue = This->updateStateBlock->textureState[Stage][Type];
3815 return WINED3D_OK;
3818 /*****
3819 * Get / Set Texture
3820 *****/
3821 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3824 IWineD3DBaseTexture *oldTexture;
3826 oldTexture = This->updateStateBlock->textures[Stage];
3827 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3829 #if 0 /* TODO: check so vertex textures */
3830 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3831 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3832 return WINED3D_OK;
3834 #endif
3836 /* Reject invalid texture units */
3837 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
3838 WARN("Attempt to access invalid texture rejected\n");
3839 return WINED3DERR_INVALIDCALL;
3842 if(pTexture != NULL) {
3843 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3845 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3846 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3847 return WINED3DERR_INVALIDCALL;
3849 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3852 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3853 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3855 This->updateStateBlock->set.textures[Stage] = TRUE;
3856 This->updateStateBlock->changed.textures[Stage] = TRUE;
3857 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3858 This->updateStateBlock->textures[Stage] = pTexture;
3860 /* Handle recording of state blocks */
3861 if (This->isRecordingState) {
3862 TRACE("Recording... not performing anything\n");
3863 return WINED3D_OK;
3866 if(oldTexture == pTexture) {
3867 TRACE("App is setting the same texture again, nothing to do\n");
3868 return WINED3D_OK;
3871 /** NOTE: MSDN says that setTexture increases the reference count,
3872 * and the the application nust set the texture back to null (or have a leaky application),
3873 * This means we should pass the refcount up to the parent
3874 *******************************/
3875 if (NULL != This->updateStateBlock->textures[Stage]) {
3876 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3877 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3879 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3880 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3881 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3882 * so the COLOROP and ALPHAOP have to be dirtified.
3884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3887 if(bindCount == 1) {
3888 new->baseTexture.sampler = Stage;
3890 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3894 if (NULL != oldTexture) {
3895 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3896 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3898 IWineD3DBaseTexture_Release(oldTexture);
3899 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3900 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3904 if(bindCount && old->baseTexture.sampler == Stage) {
3905 int i;
3906 /* Have to do a search for the other sampler(s) where the texture is bound to
3907 * Shouldn't happen as long as apps bind a texture only to one stage
3909 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3910 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3911 if(This->updateStateBlock->textures[i] == oldTexture) {
3912 old->baseTexture.sampler = i;
3913 break;
3919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3921 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3922 * pixel shader is used
3924 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3925 IWineD3DDeviceImpl_FindTexUnitMap(This);
3928 return WINED3D_OK;
3931 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3933 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3935 /* Reject invalid texture units */
3936 if (Stage >= GL_LIMITS(sampler_stages)) {
3937 TRACE("Attempt to access invalid texture rejected\n");
3938 return WINED3DERR_INVALIDCALL;
3940 *ppTexture=This->stateBlock->textures[Stage];
3941 if (*ppTexture)
3942 IWineD3DBaseTexture_AddRef(*ppTexture);
3944 return WINED3D_OK;
3947 /*****
3948 * Get Back Buffer
3949 *****/
3950 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3951 IWineD3DSurface **ppBackBuffer) {
3952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3953 IWineD3DSwapChain *swapChain;
3954 HRESULT hr;
3956 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3958 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3959 if (hr == WINED3D_OK) {
3960 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3961 IWineD3DSwapChain_Release(swapChain);
3962 } else {
3963 *ppBackBuffer = NULL;
3965 return hr;
3968 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3970 WARN("(%p) : stub, calling idirect3d for now\n", This);
3971 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3974 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3976 IWineD3DSwapChain *swapChain;
3977 HRESULT hr;
3979 if(iSwapChain > 0) {
3980 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3981 if (hr == WINED3D_OK) {
3982 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3983 IWineD3DSwapChain_Release(swapChain);
3984 } else {
3985 FIXME("(%p) Error getting display mode\n", This);
3987 } else {
3988 /* Don't read the real display mode,
3989 but return the stored mode instead. X11 can't change the color
3990 depth, and some apps are pretty angry if they SetDisplayMode from
3991 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3993 Also don't relay to the swapchain because with ddraw it's possible
3994 that there isn't a swapchain at all */
3995 pMode->Width = This->ddraw_width;
3996 pMode->Height = This->ddraw_height;
3997 pMode->Format = This->ddraw_format;
3998 pMode->RefreshRate = 0;
3999 hr = WINED3D_OK;
4002 return hr;
4005 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4007 TRACE("(%p)->(%p)\n", This, hWnd);
4009 This->ddraw_window = hWnd;
4010 return WINED3D_OK;
4013 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4015 TRACE("(%p)->(%p)\n", This, hWnd);
4017 *hWnd = This->ddraw_window;
4018 return WINED3D_OK;
4021 /*****
4022 * Stateblock related functions
4023 *****/
4025 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4027 IWineD3DStateBlockImpl *object;
4028 HRESULT temp_result;
4029 int i;
4031 TRACE("(%p)\n", This);
4033 if (This->isRecordingState) {
4034 return WINED3DERR_INVALIDCALL;
4037 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4038 if (NULL == object ) {
4039 FIXME("(%p)Error allocating memory for stateblock\n", This);
4040 return E_OUTOFMEMORY;
4042 TRACE("(%p) created object %p\n", This, object);
4043 object->wineD3DDevice= This;
4044 /** FIXME: object->parent = parent; **/
4045 object->parent = NULL;
4046 object->blockType = WINED3DSBT_ALL;
4047 object->ref = 1;
4048 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4050 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4051 list_init(&object->lightMap[i]);
4054 temp_result = allocate_shader_constants(object);
4055 if (WINED3D_OK != temp_result)
4056 return temp_result;
4058 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4059 This->updateStateBlock = object;
4060 This->isRecordingState = TRUE;
4062 TRACE("(%p) recording stateblock %p\n",This , object);
4063 return WINED3D_OK;
4066 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4069 if (!This->isRecordingState) {
4070 FIXME("(%p) not recording! returning error\n", This);
4071 *ppStateBlock = NULL;
4072 return WINED3DERR_INVALIDCALL;
4075 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4076 This->isRecordingState = FALSE;
4077 This->updateStateBlock = This->stateBlock;
4078 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4079 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4080 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4081 return WINED3D_OK;
4084 /*****
4085 * Scene related functions
4086 *****/
4087 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4088 /* At the moment we have no need for any functionality at the beginning
4089 of a scene */
4090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4091 TRACE("(%p)\n", This);
4093 if(This->inScene) {
4094 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4095 return WINED3DERR_INVALIDCALL;
4097 This->inScene = TRUE;
4098 return WINED3D_OK;
4101 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 TRACE("(%p)\n", This);
4105 if(!This->inScene) {
4106 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4107 return WINED3DERR_INVALIDCALL;
4110 ENTER_GL();
4111 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4112 glFlush();
4113 checkGLcall("glFlush");
4114 LEAVE_GL();
4116 This->inScene = FALSE;
4117 return WINED3D_OK;
4120 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4121 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4122 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 IWineD3DSwapChain *swapChain = NULL;
4125 int i;
4126 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4128 TRACE("(%p) Presenting the frame\n", This);
4130 for(i = 0 ; i < swapchains ; i ++) {
4132 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4133 TRACE("presentinng chain %d, %p\n", i, swapChain);
4134 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4135 IWineD3DSwapChain_Release(swapChain);
4138 return WINED3D_OK;
4141 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4142 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4145 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4146 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4147 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4148 GLbitfield glMask = 0;
4149 GLboolean old_ztest;
4150 GLfloat old_z_clear_value;
4151 GLint old_stencil_clear_value;
4152 GLfloat old_color_clear_value[4];
4153 unsigned int i;
4154 CONST WINED3DRECT* curRect;
4156 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4157 Count, pRects, Flags, Z, Stencil);
4159 ENTER_GL();
4161 glEnable(GL_SCISSOR_TEST);
4162 checkGLcall("glEnable GL_SCISSOR_TEST");
4164 if (Count > 0 && pRects) {
4165 curRect = pRects;
4166 } else {
4167 curRect = NULL;
4170 /* Only set the values up once, as they are not changing */
4171 if (Flags & WINED3DCLEAR_STENCIL) {
4172 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4173 glClearStencil(Stencil);
4174 checkGLcall("glClearStencil");
4175 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4176 glStencilMask(0xFFFFFFFF);
4179 if (Flags & WINED3DCLEAR_ZBUFFER) {
4180 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4181 glDepthMask(GL_TRUE);
4182 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4183 glClearDepth(Z);
4184 checkGLcall("glClearDepth");
4185 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4188 if (Flags & WINED3DCLEAR_TARGET) {
4189 TRACE("Clearing screen with glClear to color %x\n", Color);
4190 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4191 glClearColor(D3DCOLOR_R(Color),
4192 D3DCOLOR_G(Color),
4193 D3DCOLOR_B(Color),
4194 D3DCOLOR_A(Color));
4195 checkGLcall("glClearColor");
4197 /* Clear ALL colors! */
4198 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4199 glMask = glMask | GL_COLOR_BUFFER_BIT;
4202 /* Now process each rect in turn */
4203 for (i = 0; i < Count || i == 0; i++) {
4205 if (curRect) {
4206 /* Note gl uses lower left, width/height */
4207 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4208 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4209 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4210 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4211 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4212 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4213 checkGLcall("glScissor");
4214 } else {
4215 glScissor(This->stateBlock->viewport.X,
4216 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4217 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4218 This->stateBlock->viewport.Width,
4219 This->stateBlock->viewport.Height);
4220 checkGLcall("glScissor");
4223 /* Clear the selected rectangle (or full screen) */
4224 glClear(glMask);
4225 checkGLcall("glClear");
4227 /* Step to the next rectangle */
4228 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4231 /* Restore the old values (why..?) */
4232 if (Flags & WINED3DCLEAR_STENCIL) {
4233 glClearStencil(old_stencil_clear_value);
4234 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4236 if (Flags & WINED3DCLEAR_ZBUFFER) {
4237 glDepthMask(old_ztest);
4238 glClearDepth(old_z_clear_value);
4240 if (Flags & WINED3DCLEAR_TARGET) {
4241 glClearColor(old_color_clear_value[0],
4242 old_color_clear_value[1],
4243 old_color_clear_value[2],
4244 old_color_clear_value[3]);
4245 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4246 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4247 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4248 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4251 glDisable(GL_SCISSOR_TEST);
4252 checkGLcall("glDisable");
4253 LEAVE_GL();
4255 return WINED3D_OK;
4258 /*****
4259 * Drawing functions
4260 *****/
4261 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4262 UINT PrimitiveCount) {
4264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4265 This->stateBlock->streamIsUP = FALSE;
4267 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4268 debug_d3dprimitivetype(PrimitiveType),
4269 StartVertex, PrimitiveCount);
4271 if(This->stateBlock->loadBaseVertexIndex != 0) {
4272 This->stateBlock->loadBaseVertexIndex = 0;
4273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4275 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4276 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4277 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4278 return WINED3D_OK;
4281 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4282 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4283 WINED3DPRIMITIVETYPE PrimitiveType,
4284 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4287 UINT idxStride = 2;
4288 IWineD3DIndexBuffer *pIB;
4289 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4291 pIB = This->stateBlock->pIndexData;
4292 This->stateBlock->streamIsUP = FALSE;
4294 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4295 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4296 minIndex, NumVertices, startIndex, primCount);
4298 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4299 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4300 idxStride = 2;
4301 } else {
4302 idxStride = 4;
4305 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4306 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4310 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4311 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4313 return WINED3D_OK;
4316 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4317 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4318 UINT VertexStreamZeroStride) {
4319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4321 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4322 debug_d3dprimitivetype(PrimitiveType),
4323 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4325 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4326 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4327 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4328 This->stateBlock->streamIsUP = TRUE;
4329 This->stateBlock->loadBaseVertexIndex = 0;
4331 /* TODO: Only mark dirty if drawing from a different UP address */
4332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4334 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4335 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4337 /* MSDN specifies stream zero settings must be set to NULL */
4338 This->stateBlock->streamStride[0] = 0;
4339 This->stateBlock->streamSource[0] = NULL;
4341 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4342 * the new stream sources or use UP drawing again
4344 return WINED3D_OK;
4347 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4348 UINT MinVertexIndex, UINT NumVertices,
4349 UINT PrimitiveCount, CONST void* pIndexData,
4350 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4351 UINT VertexStreamZeroStride) {
4352 int idxStride;
4353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4355 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4356 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4357 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4358 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4360 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4361 idxStride = 2;
4362 } else {
4363 idxStride = 4;
4366 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4367 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4368 This->stateBlock->streamIsUP = TRUE;
4369 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4371 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4372 This->stateBlock->baseVertexIndex = 0;
4373 This->stateBlock->loadBaseVertexIndex = 0;
4374 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4377 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4379 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4380 This->stateBlock->streamSource[0] = NULL;
4381 This->stateBlock->streamStride[0] = 0;
4382 This->stateBlock->pIndexData = NULL;
4383 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4384 * SetStreamSource to specify a vertex buffer
4387 return WINED3D_OK;
4390 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4393 /* Mark the state dirty until we have nicer tracking
4394 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4395 * that value.
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4398 This->stateBlock->baseVertexIndex = 0;
4399 This->up_strided = DrawPrimStrideData;
4400 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4401 This->up_strided = NULL;
4402 return WINED3D_OK;
4404 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4405 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4407 HRESULT hr = WINED3D_OK;
4408 WINED3DRESOURCETYPE sourceType;
4409 WINED3DRESOURCETYPE destinationType;
4410 int i ,levels;
4412 /* TODO: think about moving the code into IWineD3DBaseTexture */
4414 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4416 /* verify that the source and destination textures aren't NULL */
4417 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4418 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4419 This, pSourceTexture, pDestinationTexture);
4420 hr = WINED3DERR_INVALIDCALL;
4423 if (pSourceTexture == pDestinationTexture) {
4424 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4425 This, pSourceTexture, pDestinationTexture);
4426 hr = WINED3DERR_INVALIDCALL;
4428 /* Verify that the source and destination textures are the same type */
4429 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4430 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4432 if (sourceType != destinationType) {
4433 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4434 This);
4435 hr = WINED3DERR_INVALIDCALL;
4438 /* check that both textures have the identical numbers of levels */
4439 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4440 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4441 hr = WINED3DERR_INVALIDCALL;
4444 if (WINED3D_OK == hr) {
4446 /* Make sure that the destination texture is loaded */
4447 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4449 /* Update every surface level of the texture */
4450 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4452 switch (sourceType) {
4453 case WINED3DRTYPE_TEXTURE:
4455 IWineD3DSurface *srcSurface;
4456 IWineD3DSurface *destSurface;
4458 for (i = 0 ; i < levels ; ++i) {
4459 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4460 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4461 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4462 IWineD3DSurface_Release(srcSurface);
4463 IWineD3DSurface_Release(destSurface);
4464 if (WINED3D_OK != hr) {
4465 WARN("(%p) : Call to update surface failed\n", This);
4466 return hr;
4470 break;
4471 case WINED3DRTYPE_CUBETEXTURE:
4473 IWineD3DSurface *srcSurface;
4474 IWineD3DSurface *destSurface;
4475 WINED3DCUBEMAP_FACES faceType;
4477 for (i = 0 ; i < levels ; ++i) {
4478 /* Update each cube face */
4479 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4480 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4481 if (WINED3D_OK != hr) {
4482 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4483 } else {
4484 TRACE("Got srcSurface %p\n", srcSurface);
4486 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4487 if (WINED3D_OK != hr) {
4488 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4489 } else {
4490 TRACE("Got desrSurface %p\n", destSurface);
4492 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4493 IWineD3DSurface_Release(srcSurface);
4494 IWineD3DSurface_Release(destSurface);
4495 if (WINED3D_OK != hr) {
4496 WARN("(%p) : Call to update surface failed\n", This);
4497 return hr;
4502 break;
4503 #if 0 /* TODO: Add support for volume textures */
4504 case WINED3DRTYPE_VOLUMETEXTURE:
4506 IWineD3DVolume srcVolume = NULL;
4507 IWineD3DSurface destVolume = NULL;
4509 for (i = 0 ; i < levels ; ++i) {
4510 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4511 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4512 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4513 IWineD3DVolume_Release(srcSurface);
4514 IWineD3DVolume_Release(destSurface);
4515 if (WINED3D_OK != hr) {
4516 WARN("(%p) : Call to update volume failed\n", This);
4517 return hr;
4521 break;
4522 #endif
4523 default:
4524 FIXME("(%p) : Unsupported source and destination type\n", This);
4525 hr = WINED3DERR_INVALIDCALL;
4529 return hr;
4532 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4533 IWineD3DSwapChain *swapChain;
4534 HRESULT hr;
4535 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4536 if(hr == WINED3D_OK) {
4537 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4538 IWineD3DSwapChain_Release(swapChain);
4540 return hr;
4543 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4545 /* return a sensible default */
4546 *pNumPasses = 1;
4547 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4548 FIXME("(%p) : stub\n", This);
4549 return WINED3D_OK;
4552 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4554 int j;
4555 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4556 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4557 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4558 return WINED3DERR_INVALIDCALL;
4560 for (j = 0; j < 256; ++j) {
4561 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4562 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4563 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4564 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4566 TRACE("(%p) : returning\n", This);
4567 return WINED3D_OK;
4570 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, 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 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4580 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4581 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4582 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4584 TRACE("(%p) : returning\n", This);
4585 return WINED3D_OK;
4588 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4590 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4591 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4592 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4593 return WINED3DERR_INVALIDCALL;
4595 /*TODO: stateblocks */
4596 This->currentPalette = PaletteNumber;
4597 TRACE("(%p) : returning\n", This);
4598 return WINED3D_OK;
4601 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 if (PaletteNumber == NULL) {
4604 WARN("(%p) : returning Invalid Call\n", This);
4605 return WINED3DERR_INVALIDCALL;
4607 /*TODO: stateblocks */
4608 *PaletteNumber = This->currentPalette;
4609 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4610 return WINED3D_OK;
4613 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4615 static BOOL showFixmes = TRUE;
4616 if (showFixmes) {
4617 FIXME("(%p) : stub\n", This);
4618 showFixmes = FALSE;
4621 This->softwareVertexProcessing = bSoftware;
4622 return WINED3D_OK;
4626 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4628 static BOOL showFixmes = TRUE;
4629 if (showFixmes) {
4630 FIXME("(%p) : stub\n", This);
4631 showFixmes = FALSE;
4633 return This->softwareVertexProcessing;
4637 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4639 IWineD3DSwapChain *swapChain;
4640 HRESULT hr;
4642 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4644 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4645 if(hr == WINED3D_OK){
4646 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4647 IWineD3DSwapChain_Release(swapChain);
4648 }else{
4649 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4651 return hr;
4655 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 static BOOL showfixmes = TRUE;
4658 if(nSegments != 0.0f) {
4659 if( showfixmes) {
4660 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4661 showfixmes = FALSE;
4664 return WINED3D_OK;
4667 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 static BOOL showfixmes = TRUE;
4670 if( showfixmes) {
4671 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4672 showfixmes = FALSE;
4674 return 0.0f;
4677 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4679 /** TODO: remove casts to IWineD3DSurfaceImpl
4680 * NOTE: move code to surface to accomplish this
4681 ****************************************/
4682 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4683 int srcWidth, srcHeight;
4684 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4685 WINED3DFORMAT destFormat, srcFormat;
4686 UINT destSize;
4687 int srcLeft, destLeft, destTop;
4688 WINED3DPOOL srcPool, destPool;
4689 int offset = 0;
4690 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4691 glDescriptor *glDescription = NULL;
4692 GLenum textureDimensions = GL_TEXTURE_2D;
4693 IWineD3DBaseTexture *baseTexture;
4695 WINED3DSURFACE_DESC winedesc;
4697 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4698 memset(&winedesc, 0, sizeof(winedesc));
4699 winedesc.Width = &srcSurfaceWidth;
4700 winedesc.Height = &srcSurfaceHeight;
4701 winedesc.Pool = &srcPool;
4702 winedesc.Format = &srcFormat;
4704 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4706 winedesc.Width = &destSurfaceWidth;
4707 winedesc.Height = &destSurfaceHeight;
4708 winedesc.Pool = &destPool;
4709 winedesc.Format = &destFormat;
4710 winedesc.Size = &destSize;
4712 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4714 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4715 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4716 return WINED3DERR_INVALIDCALL;
4719 if (destFormat == WINED3DFMT_UNKNOWN) {
4720 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4721 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4723 /* Get the update surface description */
4724 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4727 /* Make sure the surface is loaded and up to date */
4728 IWineD3DSurface_PreLoad(pDestinationSurface);
4730 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4732 ENTER_GL();
4734 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4735 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4736 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4737 srcLeft = pSourceRect ? pSourceRect->left : 0;
4738 destLeft = pDestPoint ? pDestPoint->x : 0;
4739 destTop = pDestPoint ? pDestPoint->y : 0;
4742 /* This function doesn't support compressed textures
4743 the pitch is just bytesPerPixel * width */
4744 if(srcWidth != srcSurfaceWidth || srcLeft ){
4745 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4746 offset += srcLeft * pSrcSurface->bytesPerPixel;
4747 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4749 /* TODO DXT formats */
4751 if(pSourceRect != NULL && pSourceRect->top != 0){
4752 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4754 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4755 ,This
4756 ,glDescription->level
4757 ,destLeft
4758 ,destTop
4759 ,srcWidth
4760 ,srcHeight
4761 ,glDescription->glFormat
4762 ,glDescription->glType
4763 ,IWineD3DSurface_GetData(pSourceSurface)
4766 /* Sanity check */
4767 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4769 /* need to lock the surface to get the data */
4770 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4773 /* TODO: Cube and volume support */
4774 if(rowoffset != 0){
4775 /* not a whole row so we have to do it a line at a time */
4776 int j;
4778 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4779 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4781 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4783 glTexSubImage2D(glDescription->target
4784 ,glDescription->level
4785 ,destLeft
4787 ,srcWidth
4789 ,glDescription->glFormat
4790 ,glDescription->glType
4791 ,data /* could be quicker using */
4793 data += rowoffset;
4796 } else { /* Full width, so just write out the whole texture */
4798 if (WINED3DFMT_DXT1 == destFormat ||
4799 WINED3DFMT_DXT2 == destFormat ||
4800 WINED3DFMT_DXT3 == destFormat ||
4801 WINED3DFMT_DXT4 == destFormat ||
4802 WINED3DFMT_DXT5 == destFormat) {
4803 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4804 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4805 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4806 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4807 } if (destFormat != srcFormat) {
4808 FIXME("Updating mixed format compressed texture is not curretly support\n");
4809 } else {
4810 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4811 glDescription->level,
4812 glDescription->glFormatInternal,
4813 srcWidth,
4814 srcHeight,
4816 destSize,
4817 IWineD3DSurface_GetData(pSourceSurface));
4819 } else {
4820 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4824 } else {
4825 glTexSubImage2D(glDescription->target
4826 ,glDescription->level
4827 ,destLeft
4828 ,destTop
4829 ,srcWidth
4830 ,srcHeight
4831 ,glDescription->glFormat
4832 ,glDescription->glType
4833 ,IWineD3DSurface_GetData(pSourceSurface)
4837 checkGLcall("glTexSubImage2D");
4838 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4840 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4841 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4842 * surface bigger than it needs to be hmm.. */
4843 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4844 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4845 IWineD3DBaseTexture_Release(baseTexture);
4848 glDisable(textureDimensions); /* This needs to be managed better.... */
4849 LEAVE_GL();
4851 return WINED3D_OK;
4854 /* Implementation details at http://developer.nvidia.com/attach/6494
4856 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4857 hmm.. no longer supported use
4858 OpenGL evaluators or tessellate surfaces within your application.
4861 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4862 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4865 FIXME("(%p) : Stub\n", This);
4866 return WINED3D_OK;
4870 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4871 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4874 FIXME("(%p) : Stub\n", This);
4875 return WINED3D_OK;
4878 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 TRACE("(%p) Handle(%d)\n", This, Handle);
4881 FIXME("(%p) : Stub\n", This);
4882 return WINED3D_OK;
4885 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4887 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4888 DDBLTFX BltFx;
4889 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4891 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4892 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4893 return WINED3DERR_INVALIDCALL;
4896 /* Just forward this to the DirectDraw blitting engine */
4897 memset(&BltFx, 0, sizeof(BltFx));
4898 BltFx.dwSize = sizeof(BltFx);
4899 BltFx.u5.dwFillColor = color;
4900 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4903 /* rendertarget and deptth stencil functions */
4904 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4907 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4908 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4909 return WINED3DERR_INVALIDCALL;
4912 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4913 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4914 /* Note inc ref on returned surface */
4915 if(*ppRenderTarget != NULL)
4916 IWineD3DSurface_AddRef(*ppRenderTarget);
4917 return WINED3D_OK;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4922 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4923 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4924 IWineD3DSwapChainImpl *Swapchain;
4925 HRESULT hr;
4927 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4929 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4930 if(hr != WINED3D_OK) {
4931 ERR("Can't get the swapchain\n");
4932 return hr;
4935 /* Make sure to release the swapchain */
4936 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4938 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4939 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4940 return WINED3DERR_INVALIDCALL;
4942 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4943 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4944 return WINED3DERR_INVALIDCALL;
4947 if(Swapchain->frontBuffer != Front) {
4948 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4950 if(Swapchain->frontBuffer)
4951 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4952 Swapchain->frontBuffer = Front;
4954 if(Swapchain->frontBuffer) {
4955 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4959 if(Back && !Swapchain->backBuffer) {
4960 /* We need memory for the back buffer array - only one back buffer this way */
4961 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4962 if(!Swapchain->backBuffer) {
4963 ERR("Out of memory\n");
4964 return E_OUTOFMEMORY;
4968 if(Swapchain->backBuffer[0] != Back) {
4969 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4970 ENTER_GL();
4971 if(!Swapchain->backBuffer[0]) {
4972 /* GL was told to draw to the front buffer at creation,
4973 * undo that
4975 glDrawBuffer(GL_BACK);
4976 checkGLcall("glDrawBuffer(GL_BACK)");
4977 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4978 Swapchain->presentParms.BackBufferCount = 1;
4979 } else if (!Back) {
4980 /* That makes problems - disable for now */
4981 /* glDrawBuffer(GL_FRONT); */
4982 checkGLcall("glDrawBuffer(GL_FRONT)");
4983 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4984 Swapchain->presentParms.BackBufferCount = 0;
4986 LEAVE_GL();
4988 if(Swapchain->backBuffer[0])
4989 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4990 Swapchain->backBuffer[0] = Back;
4992 if(Swapchain->backBuffer[0]) {
4993 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4994 } else {
4995 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5000 return WINED3D_OK;
5003 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5005 *ppZStencilSurface = This->depthStencilBuffer;
5006 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5008 if(*ppZStencilSurface != NULL) {
5009 /* Note inc ref on returned surface */
5010 IWineD3DSurface_AddRef(*ppZStencilSurface);
5012 return WINED3D_OK;
5015 static void bind_fbo(IWineD3DDevice *iface) {
5016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 if (!This->fbo) {
5019 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5020 checkGLcall("glGenFramebuffersEXT()");
5022 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5023 checkGLcall("glBindFramebuffer()");
5026 /* TODO: Handle stencil attachments */
5027 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5029 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5031 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5033 bind_fbo(iface);
5035 if (depth_stencil_impl) {
5036 GLenum texttarget, target;
5037 GLint old_binding = 0;
5039 IWineD3DSurface_PreLoad(depth_stencil);
5040 texttarget = depth_stencil_impl->glDescription.target;
5041 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5043 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5044 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5045 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5046 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5047 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5048 glBindTexture(target, old_binding);
5050 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5051 checkGLcall("glFramebufferTexture2DEXT()");
5052 } else {
5053 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5054 checkGLcall("glFramebufferTexture2DEXT()");
5057 if (!This->render_offscreen) {
5058 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5059 checkGLcall("glBindFramebuffer()");
5063 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5065 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5067 if (idx >= GL_LIMITS(buffers)) {
5068 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5071 bind_fbo(iface);
5073 if (rtimpl) {
5074 GLenum texttarget, target;
5075 GLint old_binding = 0;
5077 IWineD3DSurface_PreLoad(render_target);
5078 texttarget = rtimpl->glDescription.target;
5079 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5081 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5082 glBindTexture(target, rtimpl->glDescription.textureName);
5083 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5084 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5085 glBindTexture(target, old_binding);
5087 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5088 checkGLcall("glFramebufferTexture2DEXT()");
5090 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5091 } else {
5092 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5093 checkGLcall("glFramebufferTexture2DEXT()");
5095 This->draw_buffers[idx] = GL_NONE;
5098 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5099 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5100 checkGLcall("glDrawBuffers()");
5103 if (!This->render_offscreen) {
5104 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5105 checkGLcall("glBindFramebuffer()");
5109 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5111 WINED3DVIEWPORT viewport;
5113 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5115 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5116 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5117 return WINED3DERR_INVALIDCALL;
5120 /* MSDN says that null disables the render target
5121 but a device must always be associated with a render target
5122 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5124 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5125 for more details
5127 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5128 FIXME("Trying to set render target 0 to NULL\n");
5129 return WINED3DERR_INVALIDCALL;
5131 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5132 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);
5133 return WINED3DERR_INVALIDCALL;
5136 /* If we are trying to set what we already have, don't bother */
5137 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5138 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5139 return WINED3D_OK;
5141 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5142 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5143 This->render_targets[RenderTargetIndex] = pRenderTarget;
5145 /* Render target 0 is special */
5146 if(RenderTargetIndex == 0) {
5147 /* Finally, reset the viewport as the MSDN states. */
5148 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5149 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5150 viewport.X = 0;
5151 viewport.Y = 0;
5152 viewport.MaxZ = 1.0f;
5153 viewport.MinZ = 0.0f;
5154 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5156 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5157 * ctx properly.
5158 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5159 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5161 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5162 } else {
5163 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5164 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5166 return WINED3D_OK;
5169 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5171 HRESULT hr = WINED3D_OK;
5172 IWineD3DSurface *tmp;
5174 TRACE("(%p) Swapping z-buffer\n",This);
5176 if (pNewZStencil == This->stencilBufferTarget) {
5177 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5178 } else {
5179 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5180 * depending on the renter target implementation being used.
5181 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5182 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5183 * stencil buffer and incure an extra memory overhead
5184 ******************************************************/
5187 tmp = This->stencilBufferTarget;
5188 This->stencilBufferTarget = pNewZStencil;
5189 /* should we be calling the parent or the wined3d surface? */
5190 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5191 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5192 hr = WINED3D_OK;
5193 /** TODO: glEnable/glDisable on depth/stencil depending on
5194 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5195 **********************************************************/
5196 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5197 set_depth_stencil_fbo(iface, pNewZStencil);
5201 return hr;
5204 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5205 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5207 /* TODO: the use of Impl is deprecated. */
5208 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5210 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5212 /* some basic validation checks */
5213 if(This->cursorTexture) {
5214 ENTER_GL();
5215 glDeleteTextures(1, &This->cursorTexture);
5216 LEAVE_GL();
5217 This->cursorTexture = 0;
5220 if(pCursorBitmap) {
5221 /* MSDN: Cursor must be A8R8G8B8 */
5222 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5223 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5224 return WINED3DERR_INVALIDCALL;
5227 /* MSDN: Cursor must be smaller than the display mode */
5228 if(pSur->currentDesc.Width > This->ddraw_width ||
5229 pSur->currentDesc.Height > This->ddraw_height) {
5230 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);
5231 return WINED3DERR_INVALIDCALL;
5234 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5235 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5236 * Texture and Blitting code to draw the cursor
5238 pSur->Flags |= SFLAG_FORCELOAD;
5239 IWineD3DSurface_PreLoad(pCursorBitmap);
5240 pSur->Flags &= ~SFLAG_FORCELOAD;
5241 /* Do not store the surface's pointer because the application may release
5242 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5243 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5245 This->cursorTexture = pSur->glDescription.textureName;
5246 This->cursorWidth = pSur->currentDesc.Width;
5247 This->cursorHeight = pSur->currentDesc.Height;
5248 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5251 This->xHotSpot = XHotSpot;
5252 This->yHotSpot = YHotSpot;
5253 return WINED3D_OK;
5256 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5258 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5260 This->xScreenSpace = XScreenSpace;
5261 This->yScreenSpace = YScreenSpace;
5263 return;
5267 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5269 BOOL oldVisible = This->bCursorVisible;
5270 TRACE("(%p) : visible(%d)\n", This, bShow);
5272 if(This->cursorTexture)
5273 This->bCursorVisible = bShow;
5275 return oldVisible;
5278 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5280 TRACE("(%p) : state (%u)\n", This, This->state);
5281 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5282 switch (This->state) {
5283 case WINED3D_OK:
5284 return WINED3D_OK;
5285 case WINED3DERR_DEVICELOST:
5287 ResourceList *resourceList = This->resources;
5288 while (NULL != resourceList) {
5289 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5290 return WINED3DERR_DEVICENOTRESET;
5291 resourceList = resourceList->next;
5293 return WINED3DERR_DEVICELOST;
5295 case WINED3DERR_DRIVERINTERNALERROR:
5296 return WINED3DERR_DRIVERINTERNALERROR;
5299 /* Unknown state */
5300 return WINED3DERR_DRIVERINTERNALERROR;
5304 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5306 /** FIXME: Resource tracking needs to be done,
5307 * The closes we can do to this is set the priorities of all managed textures low
5308 * and then reset them.
5309 ***********************************************************/
5310 FIXME("(%p) : stub\n", This);
5311 return WINED3D_OK;
5314 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5315 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5317 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5318 if(surface->Flags & SFLAG_DIBSECTION) {
5319 /* Release the DC */
5320 SelectObject(surface->hDC, surface->dib.holdbitmap);
5321 DeleteDC(surface->hDC);
5322 /* Release the DIB section */
5323 DeleteObject(surface->dib.DIBsection);
5324 surface->dib.bitmap_data = NULL;
5325 surface->resource.allocatedMemory = NULL;
5326 surface->Flags &= ~SFLAG_DIBSECTION;
5328 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
5329 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
5330 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5331 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
5332 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
5333 } else {
5334 surface->pow2Width = surface->pow2Height = 1;
5335 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5336 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5338 if(surface->glDescription.textureName) {
5339 ENTER_GL();
5340 glDeleteTextures(1, &surface->glDescription.textureName);
5341 LEAVE_GL();
5342 surface->glDescription.textureName = 0;
5344 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
5345 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
5346 surface->Flags |= SFLAG_NONPOW2;
5347 } else {
5348 surface->Flags &= ~SFLAG_NONPOW2;
5350 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5351 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5354 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5356 IWineD3DSwapChainImpl *swapchain;
5357 HRESULT hr;
5358 BOOL DisplayModeChanged = FALSE;
5359 WINED3DDISPLAYMODE mode;
5360 TRACE("(%p)\n", This);
5362 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5363 if(FAILED(hr)) {
5364 ERR("Failed to get the first implicit swapchain\n");
5365 return hr;
5368 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5369 * on an existing gl context, so there's no real need for recreation.
5371 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5373 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5375 TRACE("New params:\n");
5376 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
5377 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
5378 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
5379 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
5380 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
5381 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
5382 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
5383 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
5384 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
5385 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5386 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
5387 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
5388 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
5390 /* No special treatment of these parameters. Just store them */
5391 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
5392 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
5393 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
5394 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
5396 /* What to do about these? */
5397 if(*pPresentationParameters->BackBufferCount != 0 &&
5398 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5399 ERR("Cannot change the back buffer count yet\n");
5401 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5402 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5403 ERR("Cannot change the back buffer format yet\n");
5405 if(*pPresentationParameters->hDeviceWindow != NULL &&
5406 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5407 ERR("Cannot change the device window yet\n");
5409 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5410 ERR("What do do about a changed auto depth stencil parameter?\n");
5413 if(*pPresentationParameters->Windowed) {
5414 mode.Width = swapchain->orig_width;
5415 mode.Height = swapchain->orig_height;
5416 mode.RefreshRate = 0;
5417 mode.Format = swapchain->presentParms.BackBufferFormat;
5418 } else {
5419 mode.Width = *pPresentationParameters->BackBufferWidth;
5420 mode.Height = *pPresentationParameters->BackBufferHeight;
5421 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
5422 mode.Format = swapchain->presentParms.BackBufferFormat;
5425 /* Should Width == 800 && Height == 0 set 800x600? */
5426 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
5427 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5428 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5430 WINED3DVIEWPORT vp;
5431 int i;
5433 vp.X = 0;
5434 vp.Y = 0;
5435 vp.Width = *pPresentationParameters->BackBufferWidth;
5436 vp.Height = *pPresentationParameters->BackBufferHeight;
5437 vp.MinZ = 0;
5438 vp.MaxZ = 1;
5440 if(!*pPresentationParameters->Windowed) {
5441 DisplayModeChanged = TRUE;
5443 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
5444 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
5446 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5447 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5448 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5451 /* Now set the new viewport */
5452 IWineD3DDevice_SetViewport(iface, &vp);
5455 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5456 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
5457 DisplayModeChanged) {
5458 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5461 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5462 return WINED3D_OK;
5465 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5467 /** FIXME: always true at the moment **/
5468 if(!bEnableDialogs) {
5469 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5471 return WINED3D_OK;
5475 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5477 TRACE("(%p) : pParameters %p\n", This, pParameters);
5479 *pParameters = This->createParms;
5480 return WINED3D_OK;
5483 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5484 IWineD3DSwapChain *swapchain;
5485 HRESULT hrc = WINED3D_OK;
5487 TRACE("Relaying to swapchain\n");
5489 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5490 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5491 IWineD3DSwapChain_Release(swapchain);
5493 return;
5496 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5497 IWineD3DSwapChain *swapchain;
5498 HRESULT hrc = WINED3D_OK;
5500 TRACE("Relaying to swapchain\n");
5502 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5503 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5504 IWineD3DSwapChain_Release(swapchain);
5506 return;
5510 /** ********************************************************
5511 * Notification functions
5512 ** ********************************************************/
5513 /** This function must be called in the release of a resource when ref == 0,
5514 * the contents of resource must still be correct,
5515 * any handels to other resource held by the caller must be closed
5516 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5517 *****************************************************/
5518 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5520 ResourceList* resourceList;
5522 TRACE("(%p) : resource %p\n", This, resource);
5523 #if 0
5524 EnterCriticalSection(&resourceStoreCriticalSection);
5525 #endif
5526 /* add a new texture to the frot of the linked list */
5527 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5528 resourceList->resource = resource;
5530 /* Get the old head */
5531 resourceList->next = This->resources;
5533 This->resources = resourceList;
5534 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5536 #if 0
5537 LeaveCriticalSection(&resourceStoreCriticalSection);
5538 #endif
5539 return;
5542 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5544 ResourceList* resourceList = NULL;
5545 ResourceList* previousResourceList = NULL;
5547 TRACE("(%p) : resource %p\n", This, resource);
5549 #if 0
5550 EnterCriticalSection(&resourceStoreCriticalSection);
5551 #endif
5552 resourceList = This->resources;
5554 while (resourceList != NULL) {
5555 if(resourceList->resource == resource) break;
5556 previousResourceList = resourceList;
5557 resourceList = resourceList->next;
5560 if (resourceList == NULL) {
5561 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5562 #if 0
5563 LeaveCriticalSection(&resourceStoreCriticalSection);
5564 #endif
5565 return;
5566 } else {
5567 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5569 /* make sure we don't leave a hole in the list */
5570 if (previousResourceList != NULL) {
5571 previousResourceList->next = resourceList->next;
5572 } else {
5573 This->resources = resourceList->next;
5576 #if 0
5577 LeaveCriticalSection(&resourceStoreCriticalSection);
5578 #endif
5579 return;
5583 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5585 int counter;
5587 TRACE("(%p) : resource %p\n", This, resource);
5588 switch(IWineD3DResource_GetType(resource)){
5589 case WINED3DRTYPE_SURFACE:
5590 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5591 break;
5592 case WINED3DRTYPE_TEXTURE:
5593 case WINED3DRTYPE_CUBETEXTURE:
5594 case WINED3DRTYPE_VOLUMETEXTURE:
5595 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5596 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5597 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5598 This->stateBlock->textures[counter] = NULL;
5600 if (This->updateStateBlock != This->stateBlock ){
5601 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5602 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5603 This->updateStateBlock->textures[counter] = NULL;
5607 break;
5608 case WINED3DRTYPE_VOLUME:
5609 /* TODO: nothing really? */
5610 break;
5611 case WINED3DRTYPE_VERTEXBUFFER:
5612 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5614 int streamNumber;
5615 TRACE("Cleaning up stream pointers\n");
5617 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5618 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5619 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5621 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5622 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5623 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5624 This->updateStateBlock->streamSource[streamNumber] = 0;
5625 /* Set changed flag? */
5628 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) */
5629 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5630 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5631 This->stateBlock->streamSource[streamNumber] = 0;
5634 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5635 else { /* This shouldn't happen */
5636 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5638 #endif
5642 break;
5643 case WINED3DRTYPE_INDEXBUFFER:
5644 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5645 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5646 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5647 This->updateStateBlock->pIndexData = NULL;
5650 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5651 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5652 This->stateBlock->pIndexData = NULL;
5656 break;
5657 default:
5658 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5659 break;
5663 /* Remove the resoruce from the resourceStore */
5664 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5666 TRACE("Resource released\n");
5670 /**********************************************************
5671 * IWineD3DDevice VTbl follows
5672 **********************************************************/
5674 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5676 /*** IUnknown methods ***/
5677 IWineD3DDeviceImpl_QueryInterface,
5678 IWineD3DDeviceImpl_AddRef,
5679 IWineD3DDeviceImpl_Release,
5680 /*** IWineD3DDevice methods ***/
5681 IWineD3DDeviceImpl_GetParent,
5682 /*** Creation methods**/
5683 IWineD3DDeviceImpl_CreateVertexBuffer,
5684 IWineD3DDeviceImpl_CreateIndexBuffer,
5685 IWineD3DDeviceImpl_CreateStateBlock,
5686 IWineD3DDeviceImpl_CreateSurface,
5687 IWineD3DDeviceImpl_CreateTexture,
5688 IWineD3DDeviceImpl_CreateVolumeTexture,
5689 IWineD3DDeviceImpl_CreateVolume,
5690 IWineD3DDeviceImpl_CreateCubeTexture,
5691 IWineD3DDeviceImpl_CreateQuery,
5692 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5693 IWineD3DDeviceImpl_CreateVertexDeclaration,
5694 IWineD3DDeviceImpl_CreateVertexShader,
5695 IWineD3DDeviceImpl_CreatePixelShader,
5696 IWineD3DDeviceImpl_CreatePalette,
5697 /*** Odd functions **/
5698 IWineD3DDeviceImpl_Init3D,
5699 IWineD3DDeviceImpl_Uninit3D,
5700 IWineD3DDeviceImpl_SetFullscreen,
5701 IWineD3DDeviceImpl_EnumDisplayModes,
5702 IWineD3DDeviceImpl_EvictManagedResources,
5703 IWineD3DDeviceImpl_GetAvailableTextureMem,
5704 IWineD3DDeviceImpl_GetBackBuffer,
5705 IWineD3DDeviceImpl_GetCreationParameters,
5706 IWineD3DDeviceImpl_GetDeviceCaps,
5707 IWineD3DDeviceImpl_GetDirect3D,
5708 IWineD3DDeviceImpl_GetDisplayMode,
5709 IWineD3DDeviceImpl_SetDisplayMode,
5710 IWineD3DDeviceImpl_GetHWND,
5711 IWineD3DDeviceImpl_SetHWND,
5712 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5713 IWineD3DDeviceImpl_GetRasterStatus,
5714 IWineD3DDeviceImpl_GetSwapChain,
5715 IWineD3DDeviceImpl_Reset,
5716 IWineD3DDeviceImpl_SetDialogBoxMode,
5717 IWineD3DDeviceImpl_SetCursorProperties,
5718 IWineD3DDeviceImpl_SetCursorPosition,
5719 IWineD3DDeviceImpl_ShowCursor,
5720 IWineD3DDeviceImpl_TestCooperativeLevel,
5721 /*** Getters and setters **/
5722 IWineD3DDeviceImpl_SetClipPlane,
5723 IWineD3DDeviceImpl_GetClipPlane,
5724 IWineD3DDeviceImpl_SetClipStatus,
5725 IWineD3DDeviceImpl_GetClipStatus,
5726 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5727 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5728 IWineD3DDeviceImpl_SetDepthStencilSurface,
5729 IWineD3DDeviceImpl_GetDepthStencilSurface,
5730 IWineD3DDeviceImpl_SetFVF,
5731 IWineD3DDeviceImpl_GetFVF,
5732 IWineD3DDeviceImpl_SetGammaRamp,
5733 IWineD3DDeviceImpl_GetGammaRamp,
5734 IWineD3DDeviceImpl_SetIndices,
5735 IWineD3DDeviceImpl_GetIndices,
5736 IWineD3DDeviceImpl_SetBasevertexIndex,
5737 IWineD3DDeviceImpl_SetLight,
5738 IWineD3DDeviceImpl_GetLight,
5739 IWineD3DDeviceImpl_SetLightEnable,
5740 IWineD3DDeviceImpl_GetLightEnable,
5741 IWineD3DDeviceImpl_SetMaterial,
5742 IWineD3DDeviceImpl_GetMaterial,
5743 IWineD3DDeviceImpl_SetNPatchMode,
5744 IWineD3DDeviceImpl_GetNPatchMode,
5745 IWineD3DDeviceImpl_SetPaletteEntries,
5746 IWineD3DDeviceImpl_GetPaletteEntries,
5747 IWineD3DDeviceImpl_SetPixelShader,
5748 IWineD3DDeviceImpl_GetPixelShader,
5749 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5750 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5751 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5752 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5753 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5754 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5755 IWineD3DDeviceImpl_SetRenderState,
5756 IWineD3DDeviceImpl_GetRenderState,
5757 IWineD3DDeviceImpl_SetRenderTarget,
5758 IWineD3DDeviceImpl_GetRenderTarget,
5759 IWineD3DDeviceImpl_SetFrontBackBuffers,
5760 IWineD3DDeviceImpl_SetSamplerState,
5761 IWineD3DDeviceImpl_GetSamplerState,
5762 IWineD3DDeviceImpl_SetScissorRect,
5763 IWineD3DDeviceImpl_GetScissorRect,
5764 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5765 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5766 IWineD3DDeviceImpl_SetStreamSource,
5767 IWineD3DDeviceImpl_GetStreamSource,
5768 IWineD3DDeviceImpl_SetStreamSourceFreq,
5769 IWineD3DDeviceImpl_GetStreamSourceFreq,
5770 IWineD3DDeviceImpl_SetTexture,
5771 IWineD3DDeviceImpl_GetTexture,
5772 IWineD3DDeviceImpl_SetTextureStageState,
5773 IWineD3DDeviceImpl_GetTextureStageState,
5774 IWineD3DDeviceImpl_SetTransform,
5775 IWineD3DDeviceImpl_GetTransform,
5776 IWineD3DDeviceImpl_SetVertexDeclaration,
5777 IWineD3DDeviceImpl_GetVertexDeclaration,
5778 IWineD3DDeviceImpl_SetVertexShader,
5779 IWineD3DDeviceImpl_GetVertexShader,
5780 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5781 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5782 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5783 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5784 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5785 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5786 IWineD3DDeviceImpl_SetViewport,
5787 IWineD3DDeviceImpl_GetViewport,
5788 IWineD3DDeviceImpl_MultiplyTransform,
5789 IWineD3DDeviceImpl_ValidateDevice,
5790 IWineD3DDeviceImpl_ProcessVertices,
5791 /*** State block ***/
5792 IWineD3DDeviceImpl_BeginStateBlock,
5793 IWineD3DDeviceImpl_EndStateBlock,
5794 /*** Scene management ***/
5795 IWineD3DDeviceImpl_BeginScene,
5796 IWineD3DDeviceImpl_EndScene,
5797 IWineD3DDeviceImpl_Present,
5798 IWineD3DDeviceImpl_Clear,
5799 /*** Drawing ***/
5800 IWineD3DDeviceImpl_DrawPrimitive,
5801 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5802 IWineD3DDeviceImpl_DrawPrimitiveUP,
5803 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5804 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5805 IWineD3DDeviceImpl_DrawRectPatch,
5806 IWineD3DDeviceImpl_DrawTriPatch,
5807 IWineD3DDeviceImpl_DeletePatch,
5808 IWineD3DDeviceImpl_ColorFill,
5809 IWineD3DDeviceImpl_UpdateTexture,
5810 IWineD3DDeviceImpl_UpdateSurface,
5811 IWineD3DDeviceImpl_GetFrontBufferData,
5812 IWineD3DDeviceImpl_SetupFullscreenWindow,
5813 IWineD3DDeviceImpl_RestoreWindow,
5814 /*** object tracking ***/
5815 IWineD3DDeviceImpl_ResourceReleased
5819 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5820 WINED3DRS_ALPHABLENDENABLE ,
5821 WINED3DRS_ALPHAFUNC ,
5822 WINED3DRS_ALPHAREF ,
5823 WINED3DRS_ALPHATESTENABLE ,
5824 WINED3DRS_BLENDOP ,
5825 WINED3DRS_COLORWRITEENABLE ,
5826 WINED3DRS_DESTBLEND ,
5827 WINED3DRS_DITHERENABLE ,
5828 WINED3DRS_FILLMODE ,
5829 WINED3DRS_FOGDENSITY ,
5830 WINED3DRS_FOGEND ,
5831 WINED3DRS_FOGSTART ,
5832 WINED3DRS_LASTPIXEL ,
5833 WINED3DRS_SHADEMODE ,
5834 WINED3DRS_SRCBLEND ,
5835 WINED3DRS_STENCILENABLE ,
5836 WINED3DRS_STENCILFAIL ,
5837 WINED3DRS_STENCILFUNC ,
5838 WINED3DRS_STENCILMASK ,
5839 WINED3DRS_STENCILPASS ,
5840 WINED3DRS_STENCILREF ,
5841 WINED3DRS_STENCILWRITEMASK ,
5842 WINED3DRS_STENCILZFAIL ,
5843 WINED3DRS_TEXTUREFACTOR ,
5844 WINED3DRS_WRAP0 ,
5845 WINED3DRS_WRAP1 ,
5846 WINED3DRS_WRAP2 ,
5847 WINED3DRS_WRAP3 ,
5848 WINED3DRS_WRAP4 ,
5849 WINED3DRS_WRAP5 ,
5850 WINED3DRS_WRAP6 ,
5851 WINED3DRS_WRAP7 ,
5852 WINED3DRS_ZENABLE ,
5853 WINED3DRS_ZFUNC ,
5854 WINED3DRS_ZWRITEENABLE
5857 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5858 WINED3DTSS_ADDRESSW ,
5859 WINED3DTSS_ALPHAARG0 ,
5860 WINED3DTSS_ALPHAARG1 ,
5861 WINED3DTSS_ALPHAARG2 ,
5862 WINED3DTSS_ALPHAOP ,
5863 WINED3DTSS_BUMPENVLOFFSET ,
5864 WINED3DTSS_BUMPENVLSCALE ,
5865 WINED3DTSS_BUMPENVMAT00 ,
5866 WINED3DTSS_BUMPENVMAT01 ,
5867 WINED3DTSS_BUMPENVMAT10 ,
5868 WINED3DTSS_BUMPENVMAT11 ,
5869 WINED3DTSS_COLORARG0 ,
5870 WINED3DTSS_COLORARG1 ,
5871 WINED3DTSS_COLORARG2 ,
5872 WINED3DTSS_COLOROP ,
5873 WINED3DTSS_RESULTARG ,
5874 WINED3DTSS_TEXCOORDINDEX ,
5875 WINED3DTSS_TEXTURETRANSFORMFLAGS
5878 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5879 WINED3DSAMP_ADDRESSU ,
5880 WINED3DSAMP_ADDRESSV ,
5881 WINED3DSAMP_ADDRESSW ,
5882 WINED3DSAMP_BORDERCOLOR ,
5883 WINED3DSAMP_MAGFILTER ,
5884 WINED3DSAMP_MINFILTER ,
5885 WINED3DSAMP_MIPFILTER ,
5886 WINED3DSAMP_MIPMAPLODBIAS ,
5887 WINED3DSAMP_MAXMIPLEVEL ,
5888 WINED3DSAMP_MAXANISOTROPY ,
5889 WINED3DSAMP_SRGBTEXTURE ,
5890 WINED3DSAMP_ELEMENTINDEX
5893 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5894 WINED3DRS_AMBIENT ,
5895 WINED3DRS_AMBIENTMATERIALSOURCE ,
5896 WINED3DRS_CLIPPING ,
5897 WINED3DRS_CLIPPLANEENABLE ,
5898 WINED3DRS_COLORVERTEX ,
5899 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5900 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5901 WINED3DRS_FOGDENSITY ,
5902 WINED3DRS_FOGEND ,
5903 WINED3DRS_FOGSTART ,
5904 WINED3DRS_FOGTABLEMODE ,
5905 WINED3DRS_FOGVERTEXMODE ,
5906 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5907 WINED3DRS_LIGHTING ,
5908 WINED3DRS_LOCALVIEWER ,
5909 WINED3DRS_MULTISAMPLEANTIALIAS ,
5910 WINED3DRS_MULTISAMPLEMASK ,
5911 WINED3DRS_NORMALIZENORMALS ,
5912 WINED3DRS_PATCHEDGESTYLE ,
5913 WINED3DRS_POINTSCALE_A ,
5914 WINED3DRS_POINTSCALE_B ,
5915 WINED3DRS_POINTSCALE_C ,
5916 WINED3DRS_POINTSCALEENABLE ,
5917 WINED3DRS_POINTSIZE ,
5918 WINED3DRS_POINTSIZE_MAX ,
5919 WINED3DRS_POINTSIZE_MIN ,
5920 WINED3DRS_POINTSPRITEENABLE ,
5921 WINED3DRS_RANGEFOGENABLE ,
5922 WINED3DRS_SPECULARMATERIALSOURCE ,
5923 WINED3DRS_TWEENFACTOR ,
5924 WINED3DRS_VERTEXBLEND
5927 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5928 WINED3DTSS_TEXCOORDINDEX ,
5929 WINED3DTSS_TEXTURETRANSFORMFLAGS
5932 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5933 WINED3DSAMP_DMAPOFFSET
5936 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5937 DWORD rep = StateTable[state].representative;
5938 DWORD idx;
5939 BYTE shift;
5940 UINT i;
5941 WineD3DContext *context;
5943 if(!rep) return;
5944 for(i = 0; i < This->numContexts; i++) {
5945 context = This->contexts[i];
5946 if(isStateDirty(context, rep)) continue;
5948 context->dirtyArray[context->numDirtyEntries++] = rep;
5949 idx = rep >> 5;
5950 shift = rep & 0x1f;
5951 context->isStateDirty[idx] |= (1 << shift);